如何在TypeScript中实现数组联合类型的类型收窄?
TypeScript联合数组类型收窄方案
对于定义的联合类型type MyUnion = string[] | number[],直接检查数组元素的typeof无法收窄整个数组的类型——因为TypeScript不会自动将单个元素的类型推断关联到整个数组的类型。以下是几种可行的收窄方案:
1. 自定义类型守卫(类型谓词)
这是最常用且直观的方案,通过自定义函数明确告诉TypeScript如何判断数组的具体类型:
type MyUnion = string[] | number[]; // 判断是否为字符串数组 function isStringArray(arr: MyUnion): arr is string[] { // 基础判断:数组非空且首元素为字符串 return arr.length > 0 && typeof arr[0] === "string"; // 更严谨的判断:检查所有元素(适合需要确保全量类型的场景) // return arr.every(item => typeof item === "string"); } // 判断是否为数字数组 function isNumberArray(arr: MyUnion): arr is number[] { return arr.length > 0 && typeof arr[0] === "number"; // 更严谨版本 // return arr.every(item => typeof item === "number"); } const arr: MyUnion = ["hello", "typescript"]; if (isStringArray(arr)) { // 此处arr类型已收窄为string[] console.log(arr.map(s => s.toUpperCase())); } else { // 此处arr类型已收窄为number[] console.log(arr.map(n => n * 2)); }
2. 结合every与内联类型谓词
如果不想单独定义函数,可以直接在every方法中使用内联类型谓词完成收窄:
type MyUnion = string[] | number[]; const arr: MyUnion = [1, 2, 3]; if (arr.every((item): item is string => typeof item === "string")) { // arr类型收窄为string[] arr.push("new string"); } else { // arr类型收窄为number[] arr.push(4); }
注意事项
- 若数组为空(
[]),上述基于元素的判断逻辑会进入else分支,需根据业务场景单独处理空数组的情况; - 选择基础判断(仅检查首元素)还是全量检查(every遍历),取决于你对数组类型安全性的要求——全量检查更严谨但性能略低,基础判断适合确定数组元素类型统一的场景。
内容的提问来源于stack exchange,提问作者Lars Nyström
相关产品推荐
相关产品推荐

