如何不使用字符串索引将两层深度对象值转为TypeScript联合类型?
问题原因
你之前使用的typeof obj[keyof typeof obj]写法,只会提取对象第一层属性的值类型,对当前示例来说,拿到的是两个子对象的联合类型:
type FirstLevel = { readonly aa: "A"; readonly cc: "C"; } | { readonly bb: "B"; readonly cc: "C"; }
TypeScript对联合类型做直接索引取值时,只会返回所有联合成员共有的属性对应的类型,两个子对象只有cc是公共属性,所以最终只会得到"C",无法拿到各自独有的"A"和"B"。
实现方案
不需要硬编码任何字符串索引,写一个递归的通用深度取值类型即可适配任意嵌套结构的常量对象:
// 深度提取嵌套对象所有底层值的联合类型 type DeepValueOf<T> = T extends Record<string, unknown> ? DeepValueOf<T[keyof T]> : T; // 传入对象类型直接得到结果 type ObjValue = DeepValueOf<typeof obj>; // 验证结果:type ObjValue = "A" | "B" | "C"
类型逻辑说明:
- 先判断当前传入的类型是不是对象,如果是对象,就遍历它所有键对应的值,递归传入
DeepValueOf继续下一层处理 - 条件类型遇到联合类型时会自动分发处理每个成员,不会出现之前只取公共属性的问题
- 递归到非对象类型(也就是最底层的字面量值)时直接返回,所有返回的字面量会自动合并为联合类型
- 因为你的对象已经加了
as const断言,所有值都会保留精确的字面量类型,不会被拓宽为通用string类型,最终结果和预期完全一致。
如果你的对象里存在非字符串类型的值,只想提取字符串字面量的联合,可以给终止条件加一层字符串判断:
type DeepStringValueOf<T> = T extends Record<string, unknown> ? DeepStringValueOf<T[keyof T]> : T extends string ? T : never;
内容的提问来源于stack exchange,提问作者bandor
相关产品推荐
相关产品推荐

