如何编写泛型类型从对象提取指定key的fields.default类型?
TypeScript泛型类型ThingType实现问题
问题描述
现有对象:
const test = { thing1: { name: "one", fields: { thing1Field1: { default: "text", }, thing1Field2: { default: 13, }, }, }, thing2: { name: "two", fields: { thing2Field1: { default: 12, }, }, }, };
需要编写泛型类型ThingType,接收"thing1" | "thing2"作为参数,返回对应项中fields下各字段的default值类型,期望输出:
// ThingType<"thing1"> - // { // thing1Field1: string; // thing1Field2: number; // } // ThingType<"thing2"> - // { // thing2Field1: number; // }
尝试以下代码时出现错误:"default"无法索引到typeof test[T]["fields"]
type ThingType<T extends keyof typeof test> = { [fieldName in keyof typeof test[T]["fields"]]: typeof test[T]["fields"][fieldName]["default"]; };
请问能否无需为test添加显式类型定义实现该泛型?若不能,该如何为test添加类型?
解决方案
无需显式类型定义的实现方式
错误原因是TypeScript默认类型推导无法确保typeof test[T]["fields"][fieldName]一定包含default属性,可通过条件类型+类型推断规避这个问题:
type ThingType<T extends keyof typeof test> = { [fieldName in keyof typeof test[T]["fields"]]: typeof test[T]["fields"][fieldName] extends { default: infer U } ? U : never; };
通过extends { default: infer U }明确检查字段项结构,提取default的类型U,即使TypeScript对原对象的类型推导不够精确,也能安全获取目标类型。
为test添加显式类型的实现方式
如果希望通过显式类型定义让代码逻辑更清晰,可先定义基础类型约束:
// 定义单个字段项的类型,强制包含default属性 type FieldItem<T> = { default: T; }; // 定义每个Thing的结构 type Thing = { name: string; fields: Record<string, FieldItem<any>>; }; // 为test指定精确的类型 const test: Record<"thing1" | "thing2", Thing> = { thing1: { name: "one", fields: { thing1Field1: { default: "text", }, thing1Field2: { default: 13, }, }, }, thing2: { name: "two", fields: { thing2Field1: { default: 12, }, }, }, };
此时原泛型代码即可正常工作,因为TypeScript已明确知道test[T]["fields"][fieldName]必然包含default属性:
type ThingType<T extends keyof typeof test> = { [fieldName in keyof typeof test[T]["fields"]]: typeof test[T]["fields"][fieldName]["default"]; };
内容的提问来源于stack exchange,提问作者Jeff Demanche
相关产品推荐
相关产品推荐

