@types/16.8.17
package and had problems.Type 'MutableRefObject<HTMLDivElement | undefined>' is not assignable to type 'string | ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null | undefined'.
Type 'MutableRefObject<HTMLDivElement | undefined>' is not assignable to type 'RefObject<HTMLDivElement>'.
Types of property 'current' are incompatible.
Type 'HTMLDivElement | undefined' is not assignable to type 'HTMLDivElement | null'.
Type 'undefined' is not assignable to type 'HTMLDivElement | null'.
EDIT 2: Disregard my solution, use the one below :)
I currently have the same problem, have you found a solution already by any chance?
EDIT: I'm now using this, admittedly not so pretty, solution:
const inputField = React.useRef() as React.MutableRefObject<HTMLInputElement>;
Found here: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/28884#issuecomment-471341041
A slightly neater solution is to set the initialValue to null in the useRef function call
const componentRef = useRef<HTMLDivElement>(null);
this ensures that componentRef = HTMLDivElement | null
which is what the ref prop is expecting rather than HTMLDivElement | undefined
.
@shane935 you have made my day sir 🙌🏻
Seems to me undefined
should be added to RefObject<T>.current
like:
//index.ts, line 80
interface RefObject<T> {
readonly current: T | null;
}
so it reads
//index.ts, line 80
interface RefObject<T> {
readonly current: T | null | undefined;
}
It's not a bug, it's catching a legitimate typing error.
For more details, see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/38228#issuecomment-529749802
Just as @Jessidhia say, it's not a bug , maybe you should write like this.
import React, {
forwardRef,
ForwardRefRenderFunction,
useImperativeHandle,
useRef,
PropsWithChildren,
} from "react";
interface Props {}
interface Ref {
value: string;
setValue: (value: string) => void;
}
const InputEmail: ForwardRefRenderFunction<Ref, PropsWithChildren<Props>> = (
props,
ref
) => {
// hooks
const inputElement = useRef<HTMLInputElement | null>(null);
useImperativeHandle(ref, () => {
return {
value: inputElement.current ? inputElement.current.value : "",
setValue: (value: string) => {
inputElement.current && (inputElement.current.value = value);
},
};
});
// render
return (
<div>
<input
type="text"
ref={inputElement}
defaultValue="[email protected]"
disabled
/>
</div>
);
};
const Component = forwardRef(InputEmail);
export default Component;
I'm not sure this will fix everyone's problem, and I'm no expert on this stuff, but after looking at the typings of what I was passing in as a ref and the actual ref type of the component I was passing the ref into, it seemed as though I had the interfaces wrong.
I initially had an interface of props like so for the receiving component:
type TextboxProps = CustomProps & React.HTMLProps<HTMLInputElement>
which I changed to:
type TextboxProps = CustomProps & React.HTMLAttributes<HTMLInputElement>
the typing error then disappeared.
I'm not going to pretend I know more than I do, but looking into the typings for the HTMLProps interface and the React.forwardRef() function type you can see that it is using RefAttributes
It looks like this project has 3 overloads for useRef()
, do we need all 3? It seems like the useRef<T>(null)
case is the one developers will use most of the time.
function useRef<T>(initialValue: T): MutableRefObject<T>;
function useRef<T>(initialValue: T|null): RefObject<T>;
function useRef<T = undefined>(): MutableRefObject<T | undefined>;
I have RefObject
:
I pass it to my Panel
component as the prop ref
:
I try to consume w/ forwardRef
, it becomes MutableRefObject
:
I'm now unable to consume the .current
property:
@Jessidhia @osf2e your suggestion does not seem applicable here.
The workaround I've had to resort to:
if (ref && (ref as RefObject<HTMLDivElement>).current) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(ref as RefObject<
HTMLDivElement
>)!.current!.style.height = `${containerHeight}px`;
}
Using react-native-web, I had to use.
import {RefObject} from 'react';
// ...
const myRef = useRef() as RefObject<View>
I had this problem with a Ref for an Input
element
So i switched from useRef<HTMLDivElement>()
-> useRef<HTMLInputElement>()
and it worked OK
@joshribakoff You can also type the parameters directly
export const Panel = React.forwardRef((props: PanelProps, ref: React.RefObject<HTMLDivElement>) => {
That way you shouldn't have to typecast when accessing your ref.
But I still don't understand why we have to do this...
Most helpful comment
A slightly neater solution is to set the initialValue to null in the useRef function call
const componentRef = useRef<HTMLDivElement>(null);
this ensures that componentRef =
HTMLDivElement | null
which is what the ref prop is expecting rather thanHTMLDivElement | undefined
.