Skip to content

TypeScript: a spread call of a destructured local ({...register('x')}) links to an unrelated project function #2962

Open

Description

@inth3shadows

A call to a destructured local inside a spread ({...register('email')} in JSX, or { ...register('email') } in an object) links by exact name to an unrelated project function with that name. The same call without the spread correctly links nothing.

// auth.ts
export function register(email: string): Promise<void> { return Promise.resolve(); }

// use.tsx
import { useForm } from 'react-hook-form';
export function objSpread() {
  const { register } = useForm();
  const props = { ...register('email') };          // line 4
  return props;
}
export function jsxSpread() {
  const { register } = useForm();
  return <input {...register('email')} />;          // line 9
}
export function jsxSpreadNested() {
  const { register } = useForm();
  return <form><input {...register('email')} /></form>;   // line 13
}
call edge on main expected
line 4 { ...register('email') } auth.ts register (resolvedBy: exact-match) ✗ none
line 9 <input {...register('email')} /> auth.ts register ✗ none
line 13 (nested element) auth.ts register ✗ none

Controls that already link nothing (correct):

  • const { register } = useForm(); register('email'); (no spread)
  • const { reg: register } = useForm(); register('email');
  • const register = useForm().register; register('email');, and the same local in {...register('email')}
  • const { register } = useForm(); <input ref={register('email')} /> (attribute value, not spread)

So the local-binding check that keeps a bare call off cross-file namesakes works for destructured locals, but not when the call follows .... The non-destructured local inside a spread is fine. Only destructuring and spread together fail.

Reproduced on main at 2577601, with CODEGRAPH_KERNEL=0 and with the native kernel. Linux/WSL2, Node 22.23.2. (Commits since then touch only Go, Rust and indexing.)

Why it matters. const { register } = useForm(); … <input {...register('field')} /> is react-hook-form's documented usage, so a React app using it gets one wrong edge per form field. Any project function named register (an auth register(email, password) is common) then shows every form input as a caller.

Expected. Treat the call after ... the same as the plain call: a destructured local in scope shadows cross-file namesakes.

Related: #2949 (another case where a local shadow is missed), #2676 / #2677 (destructured names in JSX children).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions