#Define a generic function parameter that accepts any interface that extends another interface

9 messages · Page 1 of 1 (latest)

fleet geyser
#

For some reason I can't get this working.
This is what I have now (it's example code):

export interface Car {
 id: number;
}

export interface Ferrari extends Car {
 name: 'Enzo'
}

export type DoSomethingFn = <T extends Car>(car: T) => unknown;

export const doingSomething: DoSomethingFn = (car: Ferrari) => { ... }

For some reason it's complaining that type Car doesn't match Ferrari due to its name property. T extends Car must not work like I expect?

heady belfry
#

Your problem stems from the parameter being in contravariant position

lunar karma
#

!:variance

weak merlinBOT
#
T6#2591
`!t6:variance`:

Here's the example with Dog and Animal, explaining co/contra/in variance:

  • Covariance: () => Dog is assignable to () => Animal, because Dog is assignable to Animal; it "preserves the direction of the assignability"
  • Contravariance: (Animal) => void is assignable to (Dog) => void, because something that expects an Animal can also take a Dog; it "reverses the direction of the assignability"
  • Invariance: (Animal) => Animal is not assignable to (Dog) => Dog, because not all returned Animals are Dogs, and (Dog) => Dog is not assignable to (Animal) => Animal, because something expecting a Dog cannot take any other kind of Animal
heady belfry
#

you’re declaring doingsomething be a function that can accept a car, then a assigning a function to it that only accepts ferraris

#

this is unsound

#

when parameters are typechecked the subtyping relation flips around

lunar karma
#

if you make the type itself generic rather than the function, that can work:

weak merlinBOT
#
That_Guy977#5882

Preview:```ts
export interface Car {
id: number
}

export interface Ferrari extends Car {
name: "Enzo"
}

export type DoSomethingFn<T extends Car> = (
car: T
) => unknown

export const doingSomething: DoSomethingFn<Ferrari> = (
car: Ferrari
) => {}```