如何为异构嵌套对象编写支持多类型返回的类型安全通用取值函数
如何为异构嵌套对象编写支持多类型返回的类型安全通用取值函数
刚好我之前也处理过类似的异构嵌套对象的类型安全取值问题,咱们一步步来拆解和解决你的需求。
首先看你原来的函数,它限定了输入是Record<T, string>——也就是所有属性值都是字符串的对象,但你的实际场景是异构嵌套对象:不同key对应的属性值类型不一样,有的是字符串,有的是嵌套对象。所以核心问题是要让函数能适配任意对象类型,并且准确返回对应key的属性类型,不管这个属性是字符串还是嵌套对象。
基础解决方案:通用泛型函数
我们可以把函数改成两个泛型参数:一个代表输入对象的类型O,另一个代表这个对象的合法keyK(K必须是O的key)。返回值直接定义为O[K],这样TypeScript就能自动推导对应属性的准确类型了。
代码实现如下:
const getConfig = <O extends object, K extends keyof O>(obj: O, key: K): O[K] => { return obj[key]; };
测试你的场景
先定义你的对象(如果想让类型更精确,比如key和字符串值都被推断为字面量类型,可以加as const断言):
const obj = { keyA: { nestedA1: "string", nestedA2: "string" }, keyB: { nestedB1: { doubleNested1: "string", doubleNested2: "string" } } } as const;
现在测试你想要的用法,完全符合预期:
getConfig(obj, "keyA"):返回的类型是{ nestedA1: "string"; nestedA2: "string" },你可以直接链式访问.nestedA1,类型完全安全。getConfig(obj.keyB, "nestedB1"):返回的是{ doubleNested1: "string"; doubleNested2: "string" },同样可以继续访问.doubleNested1。getConfig(obj.keyA, "somethingRandom"):编辑器会直接报编译错误,因为"somethingRandom"不是obj.keyA的合法key。getConfig(obj.keyB.nestedB1, "doubleNested1"):返回的是字符串类型,和你原来的函数效果一致。
扩展:支持一次性获取深层属性(可选)
如果你想一次性传入多层路径(比如keyB.nestedB1.doubleNested1)而不是分多次调用,我们可以用递归泛型实现深层路径的类型推导:
// 定义深层路径的类型:支持"key"或"key.subkey"格式 type DeepKey<T> = T extends object ? keyof T | `${keyof T & string}.${DeepKey<T[keyof T]>}` : never; // 根据深层路径推导对应的值类型 type DeepValue<T, K extends DeepKey<T>> = K extends keyof T ? T[K] : K extends `${infer First}.${infer Rest}` ? First extends keyof T ? Rest extends DeepKey<T[First]> ? DeepValue<T[First], Rest> : never : never : never; // 实现深层取值函数 const getConfigDeep = <T extends object, K extends DeepKey<T>>(obj: T, key: K): DeepValue<T, K> => { const keys = key.split('.') as Array<keyof any>; let result: any = obj; for (const k of keys) { result = result[k]; } return result; };
用法示例:
// 直接获取深层字符串,类型安全 getConfigDeep(obj, "keyB.nestedB1.doubleNested1"); // 传入错误路径会直接报错 getConfigDeep(obj, "keyB.wrongKey");
这个扩展方案能满足更复杂的深层取值场景,但如果你的需求只是分多次链式访问,基础版本就完全够用了。
备注:内容来源于stack exchange,提问作者Anne
相关产品推荐
相关产品推荐

