为什么同一类型的两个变量根据它们的产生方式而表现不同

  • 本文关键字:方式 两个 类型 变量 typescript
  • 更新时间 :
  • 英文 :


既然numsnums2都是类型(0 | 1 | 2)[],为什么tupletuple2有不同的类型?

// const nums: (0 | 1 | 2)[]
const nums: (0 | 1 | 2)[] = [];
// let tuple: (0 | 1 | 2)[]
let tuple = [nums[0], nums[1]];

// const nums2: (0 | 1 | 2)[]
const nums2 = ([] as {num?: 1 | 2}[]).
map(n => typeof n.num === "undefined" ? 0 : n.num)
// let tuple2: number[]
let tuple2 = [nums2[0], nums2[1]];

游乐场

这是在microsoft/TypeScript#11126中实现的加宽非加宽literal类型之间差异的结果。这令人困惑是可以理解的,因为IntelliSense并没有以任何不同的方式显示这些类型;它是该类型的一个不可见属性。例如,无法判断显示为0 | 1 | 2的类型是否正在加宽。


一般来说,仅出现在表达式中(而不是类型)的文字类型在可以重新分配值的地方(例如非readonly数组或元组的元素)推断时,将自动扩展到其相应的基元类型(因此0将变为number)。因此:

const nums = ([] as { num?: 1 | 2 }[]).map(n => typeof n.num === "undefined" ? 0 : n.num)
// const nums: (0 | 1 | 2)[]

nums的类型是加宽文字类型的数组,因为类型0来自表达式0,类型1 | 2来自表达式n.num,但在map()方法调用中,没有任何类型被显式写入类型。因此,当在可以重新分配的地方推断时,0 | 1 | 2扩展为number,例如数组文字:

let tuple = [nums[0], nums[1]];
// let tuple: number[]

另一方面,显式出现在类型中的文字类型(而不仅仅是表达式*)在类似情况下不会自动加宽。因此:

const nums: (0 | 1 | 2)[] = [];
// const nums: (0 | 1 | 2)[];

nums的类型是非加宽文字类型的数组,因为类型0 | 1 | 2来自nums类型注释。因此,当在一个可以重新分配的地方推断时,0 | 1 | 2不会扩展到number,例如数组文字:

let tuple = [nums[0], nums[1]];
// let tuple: (0 | 1 | 2)[];

如果希望加宽文字类型变为非加宽类型,可以在某个位置添加显式类型作为提示。类似于在表达式中显式键入其中一个值:

const nums = ([] as { num?: 1 | 2 }[]).map(n => typeof n.num === "undefined" ? 0 as 0 : n.num)
// const nums: (0 | 1 | 2)[]
let tuple = [nums[0], nums[1]];
// let tuple: (0 | 1 | 2)[];

或明确指定调用CCD_ 23 的类型参数

const nums = ([] as { num?: 1 | 2 }[]).map<0 | 1 | 2>(n => typeof n.num === "undefined" ? 0 : n.num)
// const nums: (0 | 1 | 2)[]
let tuple = [nums[0], nums[1]];
// let tuple: (0 | 1 | 2)[];

或在microsoft/TypeScript#12267内的本评论中讨论的任何方法。

游乐场链接到代码

我认为TypeScript读取:

let partOfSomeNums2 = [someNums2[1], someNums2[0]];

let partOfSomeNums2 = [0, 1];

在第二行中:partOfSomeNums2number[],就像第一行一样。

您可以使用:

let partOfSomeNums2 = [...someNums2.slice(1, 2), ...someNums2.slice(0, 1)];

或者:

let partOfSomeNums2: (0 | 1 | 2)[] = [someNums2[1], someNums2[0]];

我认为你的操场上的someWorkingFunction是有效的,因为类型0 | 1 | 2是直接从枚举中提取的,这与你的不工作代码相反,其中值0是硬编码的。

编辑

我会使用这个解决方案:游乐场

使用此类型:type SmallNumber = 0 | 1 | 2;然后,在映射函数中使用这种类型:

const someNums2 = someObjects2.map((obj): SmallNumber =>
typeof obj.num === "undefined" ? 0 : obj.num
);

相关内容

  • 没有找到相关文章