TypeScript中能否安全对数组联合类型调用Array.map方法?
数组联合类型调用map方法的类型安全解决方案
问题根源:TS 原生的 Array.prototype.map 类型定义没有处理「数组类型联合」的场景,它会先合并所有数组的元素类型,最终返回元素为联合类型的普通数组,因此无法保留原有的联合分支类型。以下是三种可行的实现方案:
方案1:封装通用的同构map工具函数
这个方案复用性最高,只需要做一次类型断言,后续所有调用都能自动推导类型:
// 工具类型:将数组联合的每个分支都做map转换 type MapArrayUnion<ArrUnion, OutputItem> = ArrUnion extends Array<infer InputItem> ? OutputItem[] : never; // 通用同构map函数 function mapHomogenous<Arr extends Array<any>, OutputItem>( arr: Arr, mapper: (item: Arr extends Array<infer InputItem> ? InputItem : never) => OutputItem ): MapArrayUnion<Arr, OutputItem> { return arr.map(mapper) as MapArrayUnion<Arr, OutputItem>; }
使用示例:
type HomogenousLetters = 'a'[] | 'b'[]; const array: HomogenousLetters = ['a', 'a', 'a'] as HomogenousLetters; // 类型推导正常,无编译错误 const mappedArray: HomogenousLetters = mapHomogenous(array, (letter) => letter);
- 优点:一次封装多次使用,调用侧不需要额外写类型断言,代码干净。
- 注意:你需要自行保证mapper函数的输出符合原数组对应的分支类型,工具函数内部的断言不会校验mapper逻辑的正确性。
方案2:直接类型断言
如果只是单次使用,不想额外封装工具,可以直接对map的返回值做类型断言:
type HomogenousLetters = 'a'[] | 'b'[]; const array: HomogenousLetters = ['a', 'a', 'a'] as HomogenousLetters; // 手动断言为目标类型 const mappedArray: HomogenousLetters = array.map((letter) => letter) as HomogenousLetters;
- 优点:写法最简单,没有额外成本。
- 缺点:每次调用都需要手动写断言,TS不会校验你的mapper逻辑是否真的保留了原数组分支类型,出错概率更高。
方案3:类型守卫缩窄后分别处理
如果想要完全的类型安全,不需要人工担保逻辑正确性,可以先通过类型守卫把数组联合缩窄到具体的分支,再分别调用map:
type HomogenousLetters = 'a'[] | 'b'[]; const array: HomogenousLetters = ['a', 'a', 'a'] as HomogenousLetters; // 定义类型守卫 function isAArray(arr: HomogenousLetters): arr is 'a'[] { return arr.every(item => item === 'a'); } function isBArray(arr: HomogenousLetters): arr is 'b'[] { return arr.every(item => item === 'b'); } const mappedArray: HomogenousLetters = isAArray(array) ? array.map(letter => letter) // 缩窄为'a'[],map返回值自动匹配'a'[] : array.map(letter => letter); // 缩窄为'b'[],map返回值自动匹配'b'[]
- 优点:完全类型安全,TS会全程校验类型正确性,不需要人工做任何担保。
- 缺点:需要为每个数组联合的分支写对应的类型守卫,分支越多成本越高。
内容的提问来源于stack exchange,提问作者David Wood
相关产品推荐
相关产品推荐

