TransWikia.com

Why does a type of T[keyof T] prevent covariance in an interface

Stack Overflow Asked by bdwain on December 20, 2021

I am trying to make a type covariant so that Type<Cat> can be treated as a Type<Animal> for example (like a list of Cats is a list of Animals). But for some reason, using the type T[keyof T] in a method in the Type interface seems to prevent that.

type Animal = {
    legs: boolean;
}

type Dog = Animal & {
    golden: boolean;
}

//This exhibits covariance
interface Comparer<T> {
    compare(a: T, b: T): number;
}

//this is valid
declare let animalComparer: CovariantComparer<Animal>;
declare let dogComparer: CovariantComparer<Dog>;

animalComparer = dogComparer;
dogComparer = animalComparer;  

//This does not
interface NonCovariantComparer<T> {
    compare(a: T, b: T[keyof T]): number;
}

declare let animalComparer2: NonCovariantComparer<Animal>;
declare let dogComparer2: NonCovariantComparer<Dog>;

animalComparer2 = dogComparer2; //typeerror
dogComparer2 = animalComparer2; //typeerror

Is there a way to make that work? Or if not, why is it impossible and is there a good pattern to get around this issue? Thanks!

Note: I’m working off of the assumption that making the object a method will make it bivariant

Typescript playground example

One Answer

Adding a generic type U extends T on the compare() method of the interface seems to resolve the errors:

type Animal = {
    legs: boolean;
}

type Dog = Animal & {
    golden: boolean;
}

interface CovariantComparer<T> {
    compare<U extends T>(a: T, b: U[keyof T]): number;
}

declare let animalComparer: CovariantComparer<Animal>;
declare let dogComparer: CovariantComparer<Dog>;

animalComparer = dogComparer;
dogComparer = animalComparer;

TypeScript Playground Link

Answered by Patrick Roberts on December 20, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP