【问题标题】:Subset shape-matching of Typescript doesnt work properlyTypescript 的子集形状匹配无法正常工作
【发布时间】:2021-05-15 13:23:16
【问题描述】:

如您所知,TypeScript 的核心原则之一是类型检查侧重于值的形状,这有时称为duck typingstructural typing。此外,形状匹配只需要匹配对象字段的子集。

例如,Typescript 完全可以接受以下代码:

interface Point {
  x: number;
  y: number;
}

function logPoint(p: Point) {
  console.log(`${p.x}, ${p.y}`);
}

const rect = { x: 33, y: 3, width: 30, height: 80 };
logPoint(rect); // logs "33, 3"

但是如果你直接用对象字面量调用 logPoint 函数,Typescript 会警告你:

logPoint({ x: 33, y: 3, width: 30, height: 80 }); // error

那么,有什么区别呢?为什么子集类型数学在第一种情况下有效而在第二种情况下无效?

链接:

Structural type system reference

First example

Second example

【问题讨论】:

  • 这能回答你的问题吗? How excess property check helps?
  • 我不知道为什么会这样。但是,尽管您可能正在使用 rect 对象做一些富有成效的事情,但根本没有实际理由使用不是精确类型匹配的文字参数。所以,我猜,要么 TS 试图保护您免受明显错误的影响,要么 TS 开发人员不想做这项工作来支持无用的用例。

标签: typescript


【解决方案1】:

这是因为 typescript 有两个级别的严格性,这取决于你想要做什么。

创建一个显式类型的对象时,typescript 会做最严格的解释,而不是你添加任何额外的属性。你的第二个例子就是这样的一个例子:在你创建这个对象文字的上下文中,它唯一可能的类型是Point,但是你给了它额外的属性,所以打字稿指出这可能是一个错误.

另一个更严格检查的例子如下。我已经明确表示我正在创建一个点,但它有额外的东西:

const rect: Point = { x: 33, y: 3, width: 30, height: 80 };

另一方面,您的第一个示例没有得到这种额外的严格性。创建对象的代码行没有指定类型,所以 typescript 自动给它类型{ x: number, y: number, width: number, height: number }。然后稍后将此对象传递给函数。与创建具有特定类型的对象不同,这种情况下打字稿只是比较类型是否“兼容”,额外的属性不会造成伤害。

【讨论】:

    【解决方案2】:

    @jonrsharpe 是对的

    它被称为:excess property check

    对象字面量在将它们分配给其他变量或将它们作为参数传递时会得到特殊处理并进行过多的属性检查。如果一个对象字面量有任何“目标类型”没有的属性,你会得到一个错误:

    如果你还想使用参考,有一个变通方法:

    interface Point {
      x: number;
      y: number;
    }
    
    type IsPoint<T> = T extends Point ? Point extends T ? T : never : never;
    
    function logPoint<T>(p: IsPoint<T>) {
      console.log(`${p.x}, ${p.y}`);
    }
    
    const rect = { x: 33, y: 3, width: 30, height: 80 };
    const rect2 = { x: 33, y: 3};
    
    logPoint(rect); // error, because Point does not extends width and height props
    
    logPoint(rect2) // ok 
    
    logPoint({ x: 33, y: 3, width: 30, height: 80 }); // error
    
    

    Playground

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-02
      • 2020-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-27
      相关资源
      最近更新 更多