如何在 TypeScript 中推断嵌套泛型类型?

4

假设我有

interface Animal {}

interface Group<A extends Animal> {}

我想使一个接口具有泛型功能,覆盖所有的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
}

我希望动物群体的道具在群体类型上是通用的。但是A扩展动物似乎是多余的。我想说:

interface AnimalGroupProps<G extends Group<A>>

让 TypeScript 自动推断。但 TypeScript 要求声明 A,因此我必须使用前面代码片段的模式。
class Wolf implements Animal {}

class WolfPack implements Group<Wolf> {}

function AnimalPlanetWolves ({withGroup, withLeader}: AnimalGroupProps<WolfPack, Wolf>) {}
//                          This is the really annoying part --------------------^^^^

所有使用AnimalGroupProps的用户都必须指定两个通用参数,尽管其中一个完全是冗余的。在我的实际代码库中,这将会非常冗长。


在上面的示例中,WolfPack不是泛型类型。如果有一个你想要传递给AnimalGroupProps的泛型类型,情况甚至更糟:

interface Flock<A extends Animal> extends Group<A> {}

class Geese implements Animal {}

function AnimalPlanetBirds ({withGroup, withLeader}: AnimalGroupProps<Flock<Geese>, Geese>) {}

Group<A> 是否有任何涉及 A 的成员?应该有。 - Aluan Haddad
@AluanHaddad 在实际使用中确实如此。以 Group 示例为例,您可以拥有 addMember: (A) => void。 - jpaddison3
所以你可以使用 interface AnimalGroupProps<G extends Group<Animal>> { withLeader: () => Parameters<G['addMember']>[0] },但在这种情况下,ccarton的答案提供了更好的方法。 - Aluan Haddad
1个回答

12
是的,TypeScript 有一种语法来推断嵌套类型。
type AnimalForGroup<G> = G extends Group<infer A> ? A : never

你仍然需要在模板参数中列出A,但可以给它设定一个默认值:
interface AnimalGroupProps<G extends Group<A>, A extends Animal = AnimalForGroup<G>> 

谢谢!我之前遇到过infer,但错误地认为它不适用。 - jpaddison3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接