转换const对象时如何保留TypeScript类型化的键与值?
保留const对象动态转换后的精确类型信息
假设有如下带as const断言的嵌套对象,它的类型是完全字面量化的:
const drinks = { cold: { juice: { name: 'orange juice', price: 2 }, water: { name: 'still water juice', price: 0 }, }, warm: { coffee: { name: 'coffee', price: 1 }, tea: { name: 'earl gray', price: 1 }, } } as const
用reduce做结构转换后,能得到扁平的目标结构,但TypeScript会把结果推断为{ [key: string]: ... },丢失了原对象的精确键和字面量类型:
const result = Object.entries(drinks).reduce( (result, [category, drinks]) => ({ ...result, ...Object.entries(drinks).reduce( (mappedItems, [name, value]) => ({ ...mappedItems, [name]: { ...value, category: category, }, }), {}, ), }), {}, )
要保留精确类型,需要手动定义类型工具并给转换结果指定类型:
步骤1:定义类型转换工具
写两个类型工具,把原嵌套结构转换成目标扁平结构的精确类型:
// 将每个分类下的饮料添加对应分类的字面量类型 type FlattenDrinks<T extends Record<string, Record<string, any>>> = { [Category in keyof T]: { [Drink in keyof T[Category]]: T[Category][Drink] & { category: Category } } }[keyof T] // 把交叉类型合并为单一对象类型 type Merge<T> = { [K in keyof T]: T[K] } // 生成最终的目标类型 type FlattenedDrinks = Merge<FlattenDrinks<typeof drinks>>
步骤2:给转换函数指定类型
修改reduce的初始值,用类型断言指定为目标类型,这样TypeScript就能识别精确的键和值类型:
const result = Object.entries(drinks).reduce( (result, [category, drinks]) => ({ ...result, ...Object.entries(drinks).reduce( (mappedItems, [name, value]) => ({ ...mappedItems, [name]: { ...value, category: category, }, }), {}, ), }), {} as FlattenedDrinks, // 断言初始值为目标类型 )
此时result的类型会精确保留所有键(juice | water | coffee | tea),每个值的category也是对应的字面量类型(比如result.juice.category类型为"cold"),同时保留原有的name和price字面量类型。
内容的提问来源于stack exchange,提问作者Theo.T
相关产品推荐
相关产品推荐

