类型可分配给“类型”类型的约束,但“类型”可以使用约束“类型”的不同子类型进行实例化

Waj*_*ath 5 typescript typescript-generics

已经有几个问题是这样问的。但我认为这更具体一点。

请看这个例子:

interface Body {
  legs: number;
}

interface Kingdom {
  animalia: {
    sound: string; // meow..
    body: Body;
  };
}

function GetBody<
  Category extends keyof Kingdom,
  B extends Kingdom[Category]["body"]
>(cat: Category): B {
  // stuff..
  return { legs: 4 }; // <==== Error!
}

// called like: GetBody('animalia').legs

Run Code Online (Sandbox Code Playgroud)

错误说:

Type '{ legs: number; }' is not assignable to type 'B'.
  '{ legs: number; }' is assignable to the constraint of type 'B', 
  but 'B' could be instantiated with a different subtype of constraint 'Body'.ts(2322)
Run Code Online (Sandbox Code Playgroud)

我在这里做错了什么?我怎样才能解决这个问题?

And*_*sta 7

您的问题是 thatB extends Kingdom[Category]["body"] 并不意味着Bis Kingdom[Category]["body"],而是意味着B必须可分配Kingdom[Category]["body"]

因此,正如 @Aluan 指出的那样,像这样的类型{legs: number, eyes: 2}对于B. {legs: number, eyes: 2} 确实延长了 Kingdom[Category]["body"]。这意味着{ legs: 4 }您返回的对象还不够。B如果确实如此,那就完美了Kingdom[Category]["body"],但情况并非总是如此。

在您的情况下,不需要通用的。事实上,使用它是错误的,因为你确实需要Kingdom[Category]["body"]

function GetBody<
  Category extends keyof Kingdom,
>(cat: Category): Kingdom[Category]["body"] {
  return { legs: 4 };
}
Run Code Online (Sandbox Code Playgroud)

注意:已经有一个 TS 接口称为Body. 改变你的名字。