Reputation: 1996
Suppose I have
interface Animal {}
interface Group<A extends Animal> {}
And I want to make an interface generic over Group
interface AnimalGroupProps<G extends Group<A>, A extends Animal> {
withGroup: () => G
// We want to be able to reference A in the interface, for use like this:
withLeader: () => A
}
I want animal group props to be generic over the group type. But the A extends Animal seems redundant. I'd like to be able to say:
interface AnimalGroupProps<G extends Group<A>>
And have TypeScript figure it out. But TypeScript wants A to be declared, so I have to use the previous snippet's pattern.
class Wolf implements Animal {}
class WolfPack implements Group<Wolf> {}
function AnimalPlanetWolves ({withGroup, withLeader}: AnimalGroupProps<WolfPack, Wolf>) {}
// This is the really annoying part --------------------^^^^
All users of AnimalGroupProps have to specify both generic parameters, even though one of them is entirely redundant. In my actual codebase, that would be a lot of redundancy.
In the above example WolfPack was not a generic type. What if there was a generic type that you wanted to pass to AnimalGroupProps? It's actually even worse:
interface Flock<A extends Animal> extends Group<A> {}
class Geese implements Animal {}
function AnimalPlanetBirds ({withGroup, withLeader}: AnimalGroupProps<Flock<Geese>, Geese>) {}
Upvotes: 4
Views: 2836
Reputation: 3666
Yes, Typescript has a syntax to infer nested types.
type AnimalForGroup<G> = G extends Group<infer A> ? A : never
You still need to list A
in the template arguments but you can give it a default value:
interface AnimalGroupProps<G extends Group<A>, A extends Animal = AnimalForGroup<G>>
Upvotes: 13