TypeScript:如何从对象数组推导以name值为键的新对象类型
从对象数组的name字段自动推断输出对象的类型键
当然可以实现,核心是利用TypeScript的泛型和字面量类型推断,让函数自动捕获传入数组中name字段的具体值,以此作为返回对象的键类型,完全不需要硬编码OutputType。
修改后的实现代码
// 定义基础项类型,name为string字面量,value为number type Item = { name: string; value: number }; // 泛型函数:捕获数组的具体类型,自动推断返回对象的键 function arrayOfObjectsToObject<T extends readonly Item[]>( array: T ): Record<T[number]['name'], { value: number }> { return array.reduce((acc, { name, value }) => { acc[name] = { value }; return acc; }, {} as Record<T[number]['name'], { value: number }>); } // 调用时,TypeScript自动推断result的类型为 { test: { value: number }; test2: { value: number } } const result = arrayOfObjectsToObject([ { name: 'test', value: 1 }, { name: 'test2', value: 2 } ]); // 直接访问result.test,TypeScript会给出正确的类型提示 console.log(result.test.value);
关键逻辑说明
- 泛型捕获数组类型:
T extends readonly Item[]让TypeScript记住传入数组的具体结构,包括每个元素name字段的字面量值(比如'test'、'test2')。 - 提取name的联合类型:
T[number]['name']从数组类型中提取所有元素name的类型,得到一个联合类型(这里是'test' | 'test2')。 - 构建返回对象类型:用TypeScript内置的
Record<Keys, Type>工具类型,创建以联合类型为键、{ value: number }为值的对象类型。 - 类型断言初始化值:因为
reduce的初始值{}默认被推断为空对象,需要用as Record<...>告诉TypeScript它最终会变成目标类型。
进阶:支持不同value类型
如果数组中每个元素的value类型不同,还可以让类型推断更精准:
function arrayOfObjectsToObject<T extends readonly { name: string; value: unknown }[]>( array: T ): { [K in T[number]['name']]: { value: Extract<T[number], { name: K }>['value'] } } { return array.reduce((acc, { name, value }) => { acc[name] = { value }; return acc; }, {} as any); } const result = arrayOfObjectsToObject([ { name: 'test', value: 1 }, { name: 'test2', value: 'hello' }, { name: 'test3', value: true } ]); // result自动推断为: // { // test: { value: number }; // test2: { value: string }; // test3: { value: boolean }; // }
原来的代码之所以需要硬编码OutputType,是因为TypeA中的name被定义为宽泛的string类型,TypeScript无法识别具体的字面量值。修改后通过泛型保留了name的字面量类型,从而实现自动推断。
内容的提问来源于stack exchange,提问作者Randall Glasgow
相关产品推荐
相关产品推荐

