为什么我不能返回一个通用的“T”来满足 Partial<T>?

Rya*_*ugh 4 generics typescript

我在 TypeScript 中写了一些代码:

type Point = {
  x: number;
  y: number;
};
function getThing<T extends Point>(p: T): Partial<T> {
  // More interesting code elided
  return { x: 10 };
}
Run Code Online (Sandbox Code Playgroud)

这会产生一个错误:

Type '{ x: 10; }' is not assignable to type 'Partial<T>'

这似乎是一个错误 -{ x: 10 }显然是一个Partial<Point>. TypeScript 在这里做错了什么?我该如何解决?

Rya*_*ugh 8

在考虑编写泛型函数时,要记住一条重要规则

调用者选择类型参数

你提供的合同getThing...

function getThing<T extends Point>(p: T): Partial<T>
Run Code Online (Sandbox Code Playgroud)

... 暗示像这样的合法调用,其中T是 的子类型Point

const p: Partial<Point3D> = getThing<Point3D>({x: 1, y: 2, z: 3});
Run Code Online (Sandbox Code Playgroud)

当然{ x: 10 } 合法的Partial<Point3D>

但是子类型化的能力不仅仅适用于添加额外的属性——子类型化可以包括选择一组更受限制的属性本身的域。你可能有这样的类型:

type UnitPoint = { x: 0 | 1, y: 0 | 1 };
Run Code Online (Sandbox Code Playgroud)

现在当你写

const p: UnitPoint = getThing<UnitPoint>({ x: 0, y: 1});
Run Code Online (Sandbox Code Playgroud)

p.x具有价值10,这是合法的UnitPoint

如果您发现自己处于这样的情况,您的返回类型实际上不是 generic 的可能性很大。更准确的函数签名是

function getThing<T extends Point>(p: T): Partial<Point> {
Run Code Online (Sandbox Code Playgroud)

  • 您可能会编写类似“&lt;T&gt;(x: T, y: T)”的内容。单参数版本没有多大意义,但有时很难说服人们他们并不真正需要泛型 (2认同)