Repository navigation
React: Type inference not working for ref callback #16019
Description
Activity
The issue here is that the type of
propsisany, sinceOtheris declared to extend fromReact.Component<any, any>. The result here is that all references to props are practically unchecked.if this component does not have any properties, then declare it as
extends React.Component<{}, any>.if the intention is to allow any property to be defined on this component, then declare at as
extends React.Component<Record<string, any>, any>.- addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bugand removedBugA bug in TypeScriptA bug in TypeScript
on May 24, 2017 simonvizzini commented
on May 24, 2017 AuthorMore actionsThank you, Mohamed Hegazy (@mhegazy)! In my concrete case I actually did have a concrete Props interface defined, I just didn't think about this when trying to come up with a minimal example (I'm still learning the nuances of the type system). Nonetheless, I'm simply unable to properly type the ref callbacks, especially when defining Props interfaces that extend other, generic props (e.g.
interface Props extends React.HTMLProps<HTMLInput>). Typescript gave funny errors along the lines of "got type A but expected B", where A extends from B, and when I changed the type def to type to B it said "got B but expected C", where B again extends from C...It's most likely a misunderstanding on my side, still learning ts and so I'll come up with a more concrete example today or tomorrow.
this works for me. if you have a sample we can look more.
interface ContainerProps { someProp: number; } class Container extends React.Component<ContainerProps, any> { render() { return <div ref={p => 0} />; // p is HTMLDivElement } } var x = <Container someProp={3} ref={p => 0} /> // p is Container
simonvizzini commented
on May 30, 2017 AuthorMore actionsThank you, your example indeed works. Finally I had time to come up with a better example that doesn't work for me. I'm probably doing something wrong I think:
interface MyInputProps extends React.ChangeTargetHTMLProps<HTMLInputElement> { onValid?(): boolean; onInvalid?(): boolean; } class MyInput extends React.Component<MyInputProps, any> { render() { const { onValid, onInvalid, ...inputProps } = this.props; return ( <input { ...inputProps } /> ); } } var x = <MyInput ref={p => 0} /> // p is any
When I try to explicitly set a type like
ref={(p: MyInput) => 0}then I get following compiler error:message: 'Type '{ ref: (p: MyInput) => number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<MyInput> & Readonly<{ children?: ReactNode; }> & R...'. Type '{ ref: (p: MyInput) => number; }' is not assignable to type 'Readonly<MyInputProps>'. Types of property 'ref' are incompatible. Type '(p: MyInput) => number' is not assignable to type 'Ref<HTMLInputElement>'. Type '(p: MyInput) => number' is not assignable to type '(instance: HTMLInputElement) => any'. Types of parameters 'p' and 'instance' are incompatible. Type 'HTMLInputElement' is not assignable to type 'MyInput'. Property 'render' is missing in type 'HTMLInputElement'.' source: 'ts'When I try to set the type to
HTMLInputElementI get:message: 'Type '{ ref: (p: MyInput) => number; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<MyInput> & Readonly<{ children?: ReactNode; }> & R...'. Type '{ ref: (p: MyInput) => number; }' is not assignable to type 'Readonly<MyInputProps>'. Types of property 'ref' are incompatible. Type '(p: MyInput) => number' is not assignable to type 'Ref<HTMLInputElement>'. Type '(p: MyInput) => number' is not assignable to type '(instance: HTMLInputElement) => any'. Types of parameters 'p' and 'instance' are incompatible. Type 'HTMLInputElement' is not assignable to type 'MyInput'.' source: 'ts'Clearly I have no idea what's going on here and I'm just randomly throwing types at my code until the compiler stops complaining 😆
Reacted by Tom Hughes, Nick Larson, Bartosz Wiśniewski, Jefferson Martins de Andrade and Gianfranco Psimonvizzini commented
on May 30, 2017 AuthorMore actionsI'm so sorry for spamming your inbox :) I think I finally figured out why TS is complaining (somehow I always missed the
Property 'render' is missing in type 'HTMLInputElement'.'part of the error message, which gave me a hint in the right direction):When I change the props interface to this:
interface MyInputProps extends React.ChangeTargetHTMLProps<MyInput & HTMLInputElement> {}
(note the
MyInput & HTMLInputElement) then the compiler is happy. Automatic type inference ofpis stillany(not sure if this is a bug or a limitation), but at least I can explicitly define the type in the ref callback now. Could you confirm if I'm doing this right?React.ChangeTargetHTMLPropsextendsReact.ClassAttributeswhich overridesrefto be a union type. here is the definition from react declaration file on DT.type Ref<T> = string | ((instance: T) => any); interface ClassAttributes<T> extends Attributes { ref?: Ref<T>; }
The result here is that there is no contextual type for the function, and this
pisany. this looks like a bug that we should fix. this should behave the same way it does with something like:declare var x: string | ((a: HTMLInputElement) =>void); x = a => { };
- addedBugA bug in TypeScriptA bug in TypeScriptand removedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on May 31, 2017 17 remaining items
would love to see this get fixed!
Reacted by Nick Larson, Nic Barker, baeharam, assin3223, Davi Medeiros and Victor Diazi am also facing similar type of issue.
ERROR
(JSX attribute) ref: React.Dispatch<(prevState: undefined) => undefined> Type 'Dispatch<(prevState: undefined) => undefined>' is not assignable to type 'LegacyRef<HTMLButtonElement>'. Type 'Dispatch<(prevState: undefined) => undefined>' is not assignable to type '(instance: HTMLButtonElement) => void'. Types of parameters 'value' and 'instance' are incompatible. Type 'HTMLButtonElement' is not assignable to type '(prevState: undefined) => undefined'. Type 'HTMLButtonElement' provides no match for the signature '(prevState: undefined): undefined'.ts(2322) index.d.ts(140, 9): The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & Props<"button", ButtonRenderPropArg, ButtonPropsWeControl>'The reported case is about the parameter not being contextually typed for this
ref. It works today so I think it's fair to close this issuecc Ryan Cavanaugh (@RyanCavanaugh) Jake Bailey (@jakebailey)
- locked as resolved and limited conversation to collaborators
on Oct 21, 2025

Type inference is not working for the
refcallback prop.I believe this is the same issue as in #7088, which was fixed over a year ago.
TypeScript Version: 2.3.2
Code
Expected behavior:
Type of parameter
refshould be inferred asTestActual behavior:
Parameter 'ref' implicitly has an 'any' type.