为什么Object.assign创建的数组类型为never[] & number[]?
TypeScript 中 Object.assign 拷贝数组的类型问题解答
先贴问题相关代码方便对照:
const arr = [1,2,3] const res1 = arr.slice() const res2 = Object.assign([],arr)
为什么 res2 的类型包含 never[]
- TypeScript 对
Object.assign的内置类型签名为:Object.assign<T, U>(target: T, source: U): T & U,返回值是入参中目标对象类型和源对象类型的交叉类型。 - 代码中传入的第一个目标参数是字面量空数组
[],在没有显式指定类型的场景下,TypeScript 默认会将空数组的类型推断为never[]:含义是这是一个不允许放入任何非never类型元素的数组。 - 第二个源参数
arr的类型是number[],两者交叉后返回值类型自然就是never[] & number[]。 - 对比之下数组原生的
slice方法的类型签名是slice(start?: number, end?: number): T[],直接返回原数组同类型的数组,所以res1的类型就是和原数组一致的number[]。
交叉类型 & 为什么能让值同时符合两种类型要求
首先要明确:TypeScript 的交叉类型不是要求值同时属于两个独立的类型,而是要求值同时具备两个类型的所有属性、满足两个类型的所有使用规则。
never是 TypeScript 中的底类型,never[]的结构和普通数组完全一致,仅对元素的写入规则做了限制。- 这里的
never[] & number[]看起来存在类型冲突,实际上是 TypeScript 没有对数组类交叉类型做额外的简化,只是保留了类型计算的原始结果,实际使用上这个交叉类型和普通的number[]完全等价:你可以正常读取number类型的元素、写入number类型的值,不会有任何类型报错。 - 从实际值的角度看,
Object.assign([], arr)是将arr的所有可枚举属性(索引、length等)复制到空数组上,最终得到的数组本身就完全符合number[]的要求,自然可以匹配交叉类型的规则。
内容的提问来源于stack exchange,提问作者Chor
相关产品推荐
相关产品推荐

