Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 233
lhk Avatar asked Oct 14 '25 08:10

lhk


1 Answers

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.

like image 85
Raphael Schweikert Avatar answered Oct 16 '25 22:10

Raphael Schweikert



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!