如何利用TypeScript提取的联合类型动态初始化对象?
问题描述
我有一个只读对象数组,通过TypeScript工具类型从中提取字段得到了联合类型RawId,并基于它定义了test类型。现在想程序化地将这个类型的所有字段初始化为0——原数组可能包含数百个元素,手动初始化实在太繁琐。
相关代码如下:
const items = [ { id: "id1", type: "raw" }, { id: "id2", type: "raw" }, { id: "id3", type: "raw" } ] as const type Item = typeof items[number] type RawId = Pick<Extract<Item, {type: 'raw'}>, 'id'>['id']; // type RawId = "id1"|"id2"|"id3" type test = {[key in RawId ]: number}; // type test = { // id1: number; // id2: number; // id3: number; // }
我试过下面的写法,但完全不生效:
const initialValue: test = { // 此写法不生效 [key in keyof typeof RawId ]: 0 }
解决方案
TypeScript的类型是编译时概念,没法直接在运行时用类型生成对象。但我们可以基于原始的items数组(运行时存在的值)来生成初始化对象,同时让TypeScript匹配到目标类型。
方法1:直接基于数组生成
先过滤出type: 'raw'的元素,再用reduce把它们的id作为键,统一赋值为0:
const initialValue: test = items .filter(item => item.type === 'raw') .reduce((acc, item) => { acc[item.id] = 0; return acc; }, {} as test);
这里用as test做类型断言是因为reduce的初始值{}默认是空对象类型,需要告诉TypeScript最终结果符合test的结构。
方法2:封装通用工具函数
如果需要多次复用这种初始化逻辑,可以写一个通用函数,自动推导目标类型:
function createInitialValue<T extends {id: string, type: string}>( items: readonly T[], targetType: string ): Record<Extract<T, {type: typeof targetType}>['id'], number> { return items .filter(item => item.type === targetType) .reduce((acc, item) => { acc[item.id] = 0; return acc; }, {} as any); } // 使用示例 const initialValue = createInitialValue(items, 'raw'); // 此时initialValue的类型会自动推导为{ id1: number; id2: number; id3: number; },和test完全一致
为什么直接用类型的写法不行?
你尝试的[key in keyof typeof RawId ]: 0写法本质错误:RawId是类型,不是运行时的值,typeof只能用于获取运行时值的类型,没法反过来操作类型。类型在编译后会被完全擦除,运行时根本不存在RawId这个东西,所以必须基于实际存在的items数组来生成对象。
内容的提问来源于stack exchange,提问作者Marko Taht
相关产品推荐
相关产品推荐

