Skip to content

Add generic type parameter for useFocusZone container ref #5449

Open
@iansan5653

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

  1. 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 makes T contravariant while the object type makes T covariant, resulting in an invariant type that accepts only exactly T. For more details on covariance and contravariance see the TypeScript documentation.

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions