lhk
lhk

Reputation: 30176

covariance in react refs and typescript generics

Typescript allows Covariance. The following code is valid, even though createElement('p') is strongly typed and returns an HTMLParagraphElement:

let p: HTMLElement = document.createElement('p');

At the same time, the following tsx code is not valid:

export default function RefProblem() {
  const myRef = useRef<HTMLElement>(null);
  return <p ref={myRef}>text</p>;
}

It produces an error message:

Type 'RefObject<HTMLElement>' is not assignable to type 'RefObject<HTMLParagraphElement>'.

This is a surprise to me, I always thought that the typechecks in Typescript would allow covariance in generic classes. So I went to the typescript playground and created this example. Everything behaves just as expected:

class A { aval: number = 0; };
class B extends A { bval: number = 0; };

let a: A = new A();
let b: B = new B();

a = b; // ok
b = a; // error

class G<T>{ gval?: T };

let ga: G<A> = new G();
let gb: G<B> = new G();

ga = gb; //ok
gb = ga; //error

Why does covariance not work for generic react refs?

Upvotes: 4

Views: 293

Answers (2)

Raphael Schweikert
Raphael Schweikert

Reputation: 18556

This is probably due to the fact that React’s typings predate TypeScript’s variance annotations.

useRef is typed to return RefObject<T>. If RefObject<T> were declared as RefObject<in T>, the check would succeed, whereas the inverse (assigning a RefObject<HTMLParagraphElement> to a ref on a <span>) wouldn’t.

Upvotes: 2

lhk
lhk

Reputation: 30176

While testing the code I realized my mistake. Maybe this will be useful to someone else, so I'll still post the question.

I thought that the reference will wrap a RefObject<HTMLParagraphElement> in the supertype RefObject<HTMLElement>. This should be fine.

But before this can happen, the react ref that has been created needs to be assigned to the JSX attribute. And here it's the inverse. I'm trying to assign a RefObject<HTMLElement> to an attribute of type RefObject<HTMLParagraphElement>.

So the typecheck makes a completely valid complaint. This should fail.

Upvotes: 0

Related Questions