TypeScript如何消除never生成合法嵌套路径联合并实现类型安全查找
解法
1. 生成所有合法路径联合
你之前的尝试得到never是因为直接拼接两个无绑定关系的联合类型时,TS会将所有组合做交叉校验,不存在同时匹配foo的二级key和bar的二级key的组合,所以最终结果为never。
使用分布式条件类型遍历每个一级键,再拼接对应一级键下的所有二级键,即可得到合法路径的联合类型:
type Structure = { foo: { a: 1, b: 2, } bar: { c: 3, d: 4, } } // 通用的两层结构合法路径生成类型 type AllValid2LevelPaths<T extends Record<string, Record<string, any>>> = { [K in keyof T]: `${K & string}.${keyof T[K] & string}` }[keyof T] // 得到的类型就是 "foo.a" | "foo.b" | "bar.c" | "bar.d" type StructurePath = AllValid2LevelPaths<Structure>
此时你可以直接使用路径联合做类型声明,不需要传泛型参数:
const path: StructurePath = 'foo.a' // 合法 const invalidPath: StructurePath = 'foo.c' // 类型报错
2. 实现类型安全的lookup函数
通过模板字面量类型拆分路径,再通过索引访问匹配对应值的类型即可:
// 通用的两层结构路径取值类型 type Get2LevelPathValue<T, P extends string> = P extends `${infer K extends keyof T & string}.${infer S extends keyof T[K] & string}` ? T[K][S] : never // 运行时函数实现(可根据你的实际取值逻辑调整) const structure: Structure = { foo: { a: 1, b: 2 }, bar: { c: 3, d: 4 } } function lookup<P extends StructurePath>(path: P): Get2LevelPathValue<Structure, P> { const [branch, section] = path.split('.') as [keyof Structure, keyof Structure[keyof Structure]] return structure[branch][section] as any } // 测试效果 const x = lookup("foo.a") // x类型自动推断为字面量 1 const y = lookup("bar.d") // y类型自动推断为字面量 4 lookup("foo.c") // 直接抛出类型错误,路径不合法
如果后续你需要支持更深层级的路径,可以把上面的两个工具类型改成递归实现即可适配任意深度的结构。
内容的提问来源于stack exchange,提问作者JD Isaacks
相关产品推荐
相关产品推荐

