【问题标题】: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 在这里做错了什么?我该如何解决这个问题?

【问题讨论】:

    标签: typescript generics


    【解决方案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 并不是要始终保持万无一失,所以这样的事情是不可避免的,但可能会令人惊讶。
    猜你喜欢
    • 1970-01-01
    • 2012-09-18
    • 2020-05-25
    • 2021-07-20
    • 1970-01-01
    相关资源
    最近更新 更多