类型推断的成功取决于命名一个值

Type inference success depends on naming a value

我对 TypeScript 还是个新手,经常发现我觉得很奇怪的东西。

取此代码:

interface MyInterface<T> {
    [i: string]: T;
}

function myFunc<T>(arg: MyInterface<T>) { }

var o = { 'val1': 42, 'val2': 43 };

myFunc(o);

呼叫失败,投诉 "Index signature is missing"。

有趣的是,我写的时候没有漏掉

myFunc({ 'val1': 42, 'val2': 43 });

这意味着表达式 { 'val1': 42, 'val2': 43 } 的类型是从调用中向后推断的(这在某种程度上是预期的),但当绑定到一个名称时则不是这样(这很奇怪而且我不知道向后例如,从 F# 推断工作)。

但它变得更加陌生。

如果我将界面更改为

interface MyInterface<T> {
    [i: number]: T;
}

然后对应的

var o = [42, 43];

myFunc(o);

也有效(除了直接传递数组)。

这是设计使然吗?解释这个的规则是什么?

您看到这种不一致的原因是因为您使用的是 TypeScript 1.8。如果您在 TypeScript playground 中尝试其中任何一个,you'll see either one works.

在 TS 1.8 中出现这种行为的原因是,当您将对象文字直接放在对 myFunc 的调用中时, [=12] 对其进行了上下文类型化=],其类型具有索引签名。结果,推断类型获得了索引签名。

上下文类型不会修改变量的先前推断类型(声明的类型),因此当您尝试将 o 传递给 myFunc 时,您收到 o 缺少索引签名的错误。

在 TypeScript 2.0(及更高版本)中,这些场景非常痛苦,因此我们引入了隐式索引签名 的概念。在此处查看拉取请求:https://github.com/Microsoft/TypeScript/pull/7029.

引用:

With this PR an object literal type is assignable to a type with an index signature if all known properties in the object literal are assignable to that index signature. This makes it possible to pass a variable that was initialized with an object literal as parameter to a function that expects a map or dictionary:

function httpService(path: string, headers: { [x: string]: string }) { }

const headers = {
    "Content-Type": "application/x-www-form-urlencoded"
};

httpService("", { "Content-Type": "application/x-www-form-urlencoded" });  // Ok
httpService("", headers);  // Now ok, previously wasn't