TypeScript 如何将数组泛型转换为其元素值的联合类型
TypeScript 泛型工具类型 ValueOf 实现方案
需求说明
我们需要实现泛型工具类型ValueOf<T>,可将满足T extends string[]的数组泛型转换为其所有元素值组成的联合类型,适配业务场景代码,保证调用transform函数时可以正确推导返回值类型。
最终实现代码
// 核心ValueOf实现,T[number]直接获取数组元素的联合类型 type ValueOf<T extends readonly string[]> = T[number]; class Foo<T extends string> { public value: T; constructor(value: T) { this.value = value; } } // 泛型加const修饰符,让TS自动推导数组字面量类型,不需要手动加as const function transform<const T extends string[]>(foo: Foo<string>, newAllowedValues: T): Foo<ValueOf<T>> { if (newAllowedValues.length === 0) { throw new Error('允许值列表不能为空'); } if (newAllowedValues.indexOf(foo.value) === -1) { foo.value = newAllowedValues[0]; } return foo as unknown as Foo<ValueOf<T>>; } let foo1 = new Foo<'a' | 'b'>('a'); // 自动推导foo2类型为 Foo<'b' | 'c'>,无需额外语法 let foo2 = transform(foo1, ['b', 'c']);
实现说明
- 核心
ValueOf<T>通过TypeScript内置的索引访问写法T[number]实现,该语法会自动遍历数组的所有数字索引,将对应位置的元素类型合并为联合类型,完全满足需求。 transform函数的泛型参数添加了const修饰符,这是TypeScript 5.0+的特性,会让编译器自动把传入的数组参数按字面量类型推导,不会拓宽为通用的string[],调用时不需要手动添加as const,适配高频调用的使用场景。
低版本TS兼容方案
如果使用的是TypeScript 5.0以下版本,去掉泛型的const修饰符,调用时给数组参数添加as const断言即可:
// 兼容TS <5.0的写法 function transform<T extends readonly string[]>(foo: Foo<string>, newAllowedValues: T): Foo<ValueOf<T>> { // 逻辑和上面实现完全一致 } // 调用时加as const let foo2 = transform(foo1, ['b', 'c'] as const);
内容的提问来源于stack exchange,提问作者Maciej Kravchyk
相关产品推荐
相关产品推荐

