为啥我不能返回一个通用的 'T' 来满足 Partial<T>?

Posted

技术标签:

【中文标题】为啥我不能返回一个通用的 \'T\' 来满足 Partial<T>?【英文标题】:Why can't I return a generic 'T' to satisfy a Partial<T>?为什么我不能返回一个通用的 'T' 来满足 Partial<T>? 【发布时间】:2022-01-24 03:45:54 【问题描述】:

我用 TypeScript 写了一些代码:

type Point = 
  x: number;
  y: number;
;
function getThing<T extends Point>(p: T): Partial<T> 
  // More interesting code elided
  return  x: 10 ;

这会产生错误:

Type ' x: 10; ' is not assignable to type 'Partial&lt;T&gt;'

这似乎是一个错误 - x: 10 显然是 Partial&lt;Point&gt;。 TypeScript 在这里做错了什么?我该如何解决这个问题?

【问题讨论】:

【参考方案1】:

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

调用者选择类型参数

你为getThing提供的合同...

function getThing<T extends Point>(p: T): Partial<T>

... 暗示像这样的合法调用,其中TPoint 的子类型:

const p: Partial<Point3D> = getThing<Point3D>(x: 1, y: 2, z: 3);

当然, x: 10 合法的Partial&lt;Point3D&gt;

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

type UnitPoint =  x: 0 | 1, y: 0 | 1 ;

现在当你写

const p: UnitPoint = getThing<UnitPoint>( x: 0, y: 1);

p.x 的值为 10不是合法的UnitPoint

如果您发现自己处于这种情况,很有可能您的返回类型实际上并不是通用的。更准确的函数签名将是

function getThing<T extends Point>(p: T): Partial<Point> 

【讨论】:

为什么有人更喜欢通用签名function getThing&lt;T extends Point&gt;(p: T): Partial&lt;Point&gt;; 而不是具体的function getThing(p: Point): Partial&lt;Point&gt;;?对文字进行过多的属性检查? 你可能会写类似&lt;T&gt;(x: T, y: T)的东西。单参数版本没有多大意义,但有时很难说服人们他们并不真的需要泛型 我们应该承认以下代码的不一致不会触发错误:function getThing&lt;T extends Point&gt;(p: T): Partial&lt;T&gt; const ret: Partial&lt;T&gt; = ; ret.x = 10; return ret; 。 TS 并不是要始终保持万无一失,所以这样的事情是不可避免的,但可能会令人惊讶。

以上是关于为啥我不能返回一个通用的 'T' 来满足 Partial<T>?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能将 const 左值引用绑定到返回 T&& 的函数?

打字稿:使用特定的扩展接口来满足通用的“扩展”类型参数?

JS中textContent和value有啥区别?同样是取值内容,为啥不能通用?

具有通用返回类型的打字稿函数

为啥 Nullable<T> 不匹配作为通用约束的引用类型 [重复]

一个 lambda 的返回类型可以通过返回值来推断,那么为啥不能是一个函数呢?