如何在TypeScript中声明转数组泛型函数并优化类型推导?
如何让TypeScript为ensureArray函数推导更精确的返回类型
我写了一个通用函数,用来把任意值包装成数组:
const ensureArray = <T>(value?: T | T[]): T[] => { if (Array.isArray(value)) return value if (value === undefined) return [] return [value] } const undef = undefined ensureArray(undef) // 结果类型为 undefined[] const str = 'string' ensureArray(str) // 结果类型为 string[] const strArray = ['string'] ensureArray(strArray) // 结果类型为 string[] interface Interface { [key: string]: string | string[] | number | number[] } const p: Interface = {a:'x'} ensureArray(p.a) // 当前推导类型:const ensureArray: <string | number>(value?: string | number | (string | number)[] | undefined) => (string | number)[]
现在希望TypeScript将该调用的类型推导为:
(value: string | number | string[] | number[] | undefined) => string[] | number[]
也就是返回值为string[]或number[],而非(string | number)[]。
解决方案1:使用条件类型
通过自定义条件类型来精确匹配输入类型,返回对应的数组类型:
type EnsureArrayReturn<T> = T extends undefined ? [] : T extends (infer U)[] ? U[] : T extends string | number ? T[] : never; const ensureArray = <T>(value?: T): EnsureArrayReturn<T> => { if (Array.isArray(value)) return value as EnsureArrayReturn<T> if (value === undefined) return [] as EnsureArrayReturn<T> return [value] as EnsureArrayReturn<T> }
测试调用效果:
const undef = undefined ensureArray(undef) // 类型为 [] const str = 'string' ensureArray(str) // 类型为 string[] const strArray = ['string'] ensureArray(strArray) // 类型为 string[] const p: Interface = {a:'x'} ensureArray(p.a) // 现在推导类型:string[] | number[]
原理说明
- 条件类型
EnsureArrayReturn<T>会根据输入的T类型分支判断:- 若
T为undefined,返回空数组类型[]; - 若
T是数组类型,直接返回该数组的元素类型数组(保留原数组类型); - 若
T是string或number,返回对应类型的数组;
- 若
- 函数内的类型断言是因为TypeScript无法自动推导条件类型的返回值,手动确认类型安全即可。
解决方案2:使用函数重载
通过重载函数明确匹配不同输入场景,返回精确类型:
function ensureArray(value: undefined): []; function ensureArray<T extends string | number>(value: T): T[]; function ensureArray<T extends string | number>(value: T[]): T[]; function ensureArray<T extends string | number>(value?: T | T[]): T[] | [] { if (Array.isArray(value)) return value if (value === undefined) return [] return [value] }
这种方式会让TypeScript根据输入的不同类型,匹配对应的重载签名,调用ensureArray(p.a)时会自动推导为string[] | number[]。
内容的提问来源于stack exchange,提问作者Michal Molhanec
相关产品推荐
相关产品推荐

