There's a small caveat with using JSX.IntrinsicElements, which is that it always includes a ref prop, even though it won't work in reality. This type is also referring to a legacy type for class-based components (LegacyRef<T>).
The better choice would be to use React.[Element]HTMLAttributes<HTML[Element]Element>, where [Element] is replace with the element type that your component wraps over, or the more explicit ComponentPropsWithRef<"button"> / ComponentPropsWithoutRef<"button">.
I prefer the former, since you don't have to think about updating the type of your Props in case you either wrap or unwrap your component forwardRef, which will return the correct type.
To explain further: Using JSX.IntrinsicElements will give you incorrect type information for props:
There's a small caveat with using
JSX.IntrinsicElements
, which is that it always includes aref
prop, even though it won't work in reality. This type is also referring to a legacy type for class-based components (LegacyRef<T>
).The better choice would be to use
React.[Element]HTMLAttributes<HTML[Element]Element>
, where[Element]
is replace with the element type that your component wraps over, or the more explicitComponentPropsWithRef<"button">
/ComponentPropsWithoutRef<"button">
.I prefer the former, since you don't have to think about updating the type of your Props in case you either wrap or unwrap your component
forwardRef
, which will return the correct type.To explain further: Using
JSX.IntrinsicElements
will give you incorrect type information for props:Passing anything to
ref
will throw a warning in development mode:This is because it has not been forwarded by our wrapper component.
It also refers to the incorrect type
LegacyRef<T>
which acceptsstring
which are legacy as mentioned in the Ref and the DOM.It's by built-in JSX elements to be backwards-compatible with earlier versions of the React API.
However, using the
React.[Element]HTMLAttributes<HTML[Element]Element>
instead:Gives us the correct type information; that
ref
is not present since it doesn't take any refs.If you'd like to accept a
ref
and pass it down to the underlying element, you want to useforwardRef
:Note that the type for
ref
prop is nowRef<T>
, which conforms correctly to whatuseRef
andcreateRef
returns (RefCallback<T> | RefObject<T>
).Hope this helps :-)