Michael Lorton
Michael Lorton

Reputation: 44416

Covariant self-referential types

I am trying to make a properly typesafe binary tree, and here is where I am:

class BinaryNode<N extends BinaryNode<N>> {
    constructor(left?: N, right?: N) {}
}

class A extends BinaryNode<A> { }
class B extends BinaryNode<B> { }


const leafA = new A();
const leafB = new B();
const rootA = new A(leafA, leafB);

The problem is, this compiles. I don't think it should: the A contractor should take two (or fewer) As, and nothing else.

More importantly, how do I do this? I want the result to be a homogeneous tree of As, enforced by the compiler.

Upvotes: 1

Views: 53

Answers (1)

artem
artem

Reputation: 51719

TypeScript type system is structural. That means that for typechecking, your A and B classes are the same. If you make them different, you will get the error:

class BinaryNode<N extends BinaryNode<N>> {
    constructor(left?: N, right?: N) {}
}

class A extends BinaryNode<A> { a: string }
class B extends BinaryNode<B> { b: string }


const leafA = new A();
const leafB = new B();
const rootA = new A(leafA, leafB);  // Argument of type 'B' is not
                                   // assignable to parameter of type 'A'.
                                  //  Property 'a' is missing in type 'B'.

Upvotes: 3

Related Questions