TypeScript如何定义单一类型联合数组及解决类型收窄问题?
解决方案
1. 声明纯string/纯number数组的类型
你的思路是正确的,直接使用联合类型即可:
// 两种写法等价,推荐简写形式 let a: number[] | string[]; // 或者 let b: Array<number> | Array<string>;
TypeScript会自动推断纯类型数组的类型,比如直接赋值let c = [1,2,3]时,类型会被推断为number[],只有当变量需要兼容两种纯类型数组时,才需要显式声明联合类型。
2. 将联合类型数组转换为number数组
需要先判断数组的实际类型,再进行转换或直接赋值,推荐使用类型守卫实现类型收窄:
情况1:数组本身是number数组,直接赋值
let a: number[] | string[]; let b: number[]; // 自定义类型守卫函数 function isNumberArray(arr: number[] | string[]): arr is number[] { // 非空数组时检查第一个元素类型,空数组可根据需求处理 return arr.length > 0 && typeof arr[0] === 'number'; } if (isNumberArray(a)) { b = a; // 此时a已被TypeScript认定为number[] }
情况2:数组是string数组,转换为number数组
如果确定string数组中的元素都可转换为数字,使用map配合Number转换:
else { // 转换为number数组,注意:无法转换的字符串会得到NaN b = a.map(item => Number(item)); }
3. 解决Date[]/number[]类型收窄的编译错误
仅通过arr[0] instanceof Date无法让TypeScript推断整个数组都是Date[],因为TypeScript不会默认假设数组所有元素类型与第一个元素一致。推荐以下两种解决方法:
方案1:自定义数组级类型守卫(推荐,安全且符合ESLint规则)
// 类型守卫:判断数组所有元素都是Date function isDateArray(arr: Date[] | number[]): arr is Date[] { return arr.every(item => item instanceof Date); } function f(arr: Date[] | number[]) { if (isDateArray(arr)) { g(arr[0]); g(arr[1]); // 此处无编译错误,arr已被收窄为Date[] } } function g(e: Date): void {}
方案2:类型断言配合前置检查(适合确定数组非空且元素类型统一的场景)
如果能保证数组非空且所有元素类型与第一个元素一致,可先将数组断言为Date[]再检查,既避免编译错误,也能通过ESLint检查:
function f(arr: Date[] | number[]) { const dateArr = arr as Date[]; if (dateArr[0] instanceof Date) { g(dateArr[0]); g(dateArr[1]); } }
内容的提问来源于stack exchange,提问作者maplemaple
相关产品推荐
相关产品推荐

