Add generic type parameter for useFocusZone
container ref #5449
Description
The type of the containerRef
returned from useFocusZone
is RefObject<HTMLElement>
. This prevents it from being assigned to any actual HTML elements, because HTML element ref prop types are invariant1. If you attempt to do the following you'll get a TypeScript error:
const {containerRef} = useFocusZone()
return <div ref={containerRef}>...</div>
Type 'RefObject<HTMLElement>' is not assignable to type 'LegacyRef<HTMLDivElement> | undefined'.
Type 'RefObject<HTMLElement>' is not assignable to type 'RefObject<HTMLDivElement>'.
Property 'align' is missing in type 'HTMLElement' but required in type 'HTMLDivElement'.
Currently the only workaround is a typecast (containerRef as RefObject<HTMLDivElement>
) or defining the ref outside the hook using useRef
.
This could easily be fixed by adding a generic type parameter to useFocusZone
so that the consumer could define an element type to be used, for example:
const {containerRef} = useFocusZone<HTMLDivElement>()
return <div ref={containerRef}>...</div>
Footnotes
-
This is surprising, but it happens because HTML element
ref
props accept both object and callback refs. Thus they are typed as (with some simplification)(element: T | null) => void | {current: T | null}
. The function type makesT
contravariant while the object type makesT
covariant, resulting in an invariant type that accepts only exactlyT
. For more details on covariance and contravariance see the TypeScript documentation. ↩