【问题标题】:Generic function allow arbitrary keys通用函数允许任意键
【发布时间】:2017-08-24 17:54:31
【问题描述】:

为什么下面的代码编译成功?由于bar 不是MyState 的一部分,我预计它会产生编译器错误。

type MyState = { foo: number; };
type Reducer<T> = (state: T) => T;

const wtf: Reducer<MyState> = (state) => {
  return { foo: 123, bar: 123 }; // `bar` isn't part of MyState
};

【问题讨论】:

  • 为什么会这样。 MyState 只需要 foo,如果它有更多,它仍然满足 MyState 的定义。
  • @ErikPhilips 编译器会抱怨:const myState: MyState = { foo: 123, bar: 123 }; 并会说“对象文字只能指定已知属性,而 'bar' 不存在于类型 'MyState' 中。”

标签: typescript


【解决方案1】:

crashmstr 的回答是正确的,但值得解释为什么这种情况与您确实出错的情况不同。

对象字面量仅在特定情况下会导致额外的属性错误。

在这种情况下:

var x: MyState = { foo: 10, bar: 20 };

类型系统执行以下步骤:

  • 检查 MyState 是否为有效类型(确实如此)
  • 检查初始化程序是否有效:
    • 初始化程序的类型是什么?
      • 新鲜对象类型{foo: 10, bar: 20}
    • 是否可以分配给MyState
      • foo 属性吗?
        • 是的
      • 它的类型匹配吗?
        • 是的 (10 -> number)
      • 新类型是否有任何额外的属性?
        • 是的
          • 错误

这里的关键是新鲜度。来自对象文字的类型是新鲜,如果它直接来自对象文字本身。这意味着两者之间存在差异

// Error
var x: MyState = { foo: 10, bar: 20 };

// OK
var x1 = { foo: 10, bar: 20 };
var x2: MyState = x1;

因为对象字面量的新鲜度在分配到x1 后就消失了。

您的示例遭受了同样的命运 - 一旦对象文字成为函数返回类型的一部分,它的新鲜感就消失了。这也解释了为什么如果函数表达式上有返回类型注释,错误会再次出现。

【讨论】:

  • 除了名义上的打字外,是否有任何计划允许对此类情况进行更多的声音限制?
  • 这不是健全性缺陷。没有观察到错误的类型;该函数返回一个正确的子类型。
  • 对不起,我可能天真地使用了“声音”这个词。我只是想防止在我的减速器中出现拼写错误,但在当前的类型系统中,这被证明是困难的。
【解决方案2】:

TypeScript 中的类型兼容性基于结构子类型。结构类型是一种仅基于其成员关联类型的方法。这与名义类型不同。

Type Compatibility

为了检查 y 是否可以分配给 x,编译器检查 x 的每个属性以在 y 中找到对应的兼容属性。在这种情况下, y 必须有一个名为 name 的成员,它是一个字符串。确实如此,因此允许分配。请注意, y 有一个额外的 location 属性,但这不会产生错误。检查兼容性时,仅考虑目标类型(在本例中为命名)的成员。

因此,在您的示例中,{ foo: 123, bar: 123 } 满足具有作为数字的 foo 的要求,并且为了类型兼容性而忽略了额外的 bar

注意:另见Why am I getting an error “Object literal may only specify known properties”?

【讨论】:

  • 那为什么编译器会报错呢? const wtf2 (state: MyState) : MyState =&gt; { return { foo: 123, bar: 123 }; 它说,“对象字面量只能指定已知属性,而 'bar' 在 'MyState' 类型中不存在。”
  • @crashmstr 我投了反对票,因为当我们使用同一函数的非泛型形式时编译器会抱怨。答案没有说明为什么泛型形式允许未知属性,而非泛型形式不允许未知属性。
  • 嗯,特别是有一种情况,Object Literals 被保持在更高的标准,我不知道在文档中指定的位置。这也不是当前问题的一部分,只是一个评论。
  • 问题的函数实现返回一个对象字面量,因此对象字面量是当前问题的一部分。
猜你喜欢
  • 2014-04-14
  • 2015-08-14
  • 2011-04-04
  • 1970-01-01
  • 2013-06-21
  • 2020-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多