首页 > 解决方案 > 为什么将变量重新分配给新对象时类型推断不适用于对象属性?

问题描述

为什么将变量重新分配给新对象时类型推断不适用于对象属性?

示例(TypeScript v3.4.5):

// compiles
let myVar: string | number;
myVar = '5';
console.log(myVar.length);

// compiles
let myObj1: {myProp: string | number} = {myProp: 5};
myObj1.myProp = '5';
console.log(myObj1.myProp.length);

// does not compile, emitting the following error:
// TSError: ⨯ Unable to compile TypeScript:
// myt.ts(63,26): error TS2339: Property 'length' does not exist on type 'string | number'.
//   Property 'length' does not exist on type 'number'.
let myObj2: {myProp: string | number} = {myProp: 5};
myObj2 = {myProp: '5'};
console.log(myObj2.myProp.length);

标签: typescript

解决方案


我认为这里发生的情况是,缩小分配的规则仅适用于联合类型的值,无论好坏:

将类型值赋值给类型变量的赋值(包括声明中的初始化程序)S会将该变量的类型T更改为在赋值之后的代码路径中T缩小范围。S

[剪辑]

T缩小的类型S计算如下:

  • 如果T不是联合类型,则结果为T
  • 如果T是联合类型,则结果是可分配的每个组成类型的T联合S

有人建议取消这个限制,但现在就是这样。

另请注意,类型A | B是联合,而类型{x: A | B}不是。是的,{x: A | B}有一个类型是联合类型的属性,但它本身不是联合类型。


那么让我们看看这里发生了什么:

let myObj1: { myProp: string | number } = { myProp: 5 };

好的,这是分配一个非联合类型的值。所以我们可以期待这里不会缩小。让我们确保:

myObj1.myProp.toFixed(); // error!

是的,没有缩小。继续:

myObj1.myProp = "5";

好的,这是分配一个 type 的值string | number,一个联合类型。所以我们可以预期这里会缩小。让我们确保:

console.log(myObj1.myProp.length); // no error

是的,缩小。然后是其余的:

let myObj2: { myProp: string | number } = { myProp: 5 };
myObj2 = { myProp: "5" };

这些都是分配非联合类型的值......所以,没有缩小:

myObj2.myProp.length; // error!

是的,没有缩小。


所以这可能是为什么会发生这种情况的规范解释。至于是否应该对所有分配进行缩小...如果您认为应该这样做,您可能需要转到相关的 Github 问题,microsoft/TypeScript#27706,如果您认为它特别引人注目,请给它一个或描述您的用例。

好的,希望有帮助;祝你好运!

链接到代码


推荐阅读