如何在TypeScript中实现元组的泛型函数分发映射?
实现保留元组长度与类型窄化的
map函数 核心解决方案
通过泛型映射类型结合函数参数的类型推断,可以实现严格保留元组长度和窄化类型的map函数。以下是两种可行实现:
方案1:通用映射类型方案
// 定义元组映射类型,针对每个元素应用函数的返回类型 type MapTuple<T extends readonly any[], F> = { [K in keyof T]: F extends (arg: T[K]) => infer R ? R : never; }; function mapTuple<T extends readonly any[], F extends (arg: any) => any>( tuple: T, func: F ): MapTuple<T, F> { // 手动断言类型,因为Array.map默认返回数组而非元组 return tuple.map(func as any) as MapTuple<T, F>; } // 测试示例 const input = ["a", "b", "c"] as const; const result = mapTuple(input, (e) => `__${e}` as const); // result类型为:["__a", "__b", "__c"]
方案2:针对特定映射规则的简化方案
如果已知映射规则(比如固定前缀拼接),可以直接构造字面量类型映射,更直观:
function mapTuple<T extends readonly string[]>( tuple: T, func: <U extends T[number]>(arg: U) => `__${U}` ): { [K in keyof T]: `__${T[K]}` } { return tuple.map(func as any) as any; } // 测试示例 const input = ["a", "b", "c"] as const; const result = mapTuple(input, e => `__${e}` as const); // result类型为:["__a", "__b", "__c"]
关键原理说明
- 避免类型拓宽:必须在映射函数的返回值后添加
as const,强制TS保留字符串字面量类型,否则__${e}会被自动拓宽为string类型。 - 映射类型遍历元组:通过
[K in keyof T]遍历元组的每个索引,确保输出元组与输入元组长度完全一致。 - 泛型函数的类型匹配:方案1中利用
F extends (arg: T[K]) => infer R,让TS针对每个元组元素的具体类型,推断函数对应的返回类型,解决了直接实例化泛型函数导致的类型丢失问题。
注意事项
- 由于TS内置的
Array.map返回值是数组类型而非元组,因此需要通过类型断言将结果转换为我们定义的元组类型。 - 若映射函数的逻辑更复杂,只需确保函数的泛型参数能正确关联输入元素的字面量类型,即可保留窄化后的输出类型。
内容的提问来源于stack exchange,提问作者dsalex1
相关产品推荐
相关产品推荐

