关于TypeScript递归数组类型声明与嵌套属性导航泛型方法类型约束的技术问询
TypeScript递归数组类型声明与嵌套属性导航泛型方法类型约束的技术问询
嘿,这个需求我太熟了——本质就是要让TypeScript帮你在编译阶段就把嵌套属性路径的合法性校验好,同时实现安全的属性导航对吧?我来给你一步步拆解怎么实现这个泛型方法。
首先核心问题是定义那个someType,也就是能描述所有合法嵌套属性路径的数组类型。我们需要一个递归的类型来遍历对象的每一层属性,生成所有可能的路径组合:
// 递归生成所有合法的嵌套属性路径数组类型 type NestedKeyPath<T> = T extends object ? { [K in keyof T]: [K] | [K, ...NestedKeyPath<T[K]>] }[keyof T] : never;
这个类型的逻辑很简单:如果传入的T是对象类型,就遍历它的每个属性K,生成两种路径——要么是单独的[K](对应第一层属性),要么是[K, ...后续嵌套路径](对应深入到下一层的属性);最后通过[keyof T]把所有可能的路径合并成一个联合类型。如果T不是对象,就返回never表示没有合法路径。
接下来就是实现泛型方法了,我们用上面的NestedKeyPath<T>来约束arrayAttr的类型,同时实现属性导航的逻辑:
function navigate<T>(instance: T, arrayAttr: NestedKeyPath<T>): unknown { let current: any = instance; for (const attr of arrayAttr) { current = current[attr]; // 可以加个运行时兜底,防止属性不存在导致的崩溃 if (current === undefined) break; } return current; }
现在用你给的例子测试一下:
const obj = { attribute1: { attribute2: { attribute3: "value" } } }; // 完全合法的调用,返回"value",编译无错误 const result = navigate(obj, ['attribute1', 'attribute2', 'attribute3']); console.log(result); // 输出 "value" // 非法调用,编译阶段直接报错!因为'attribute3'不在obj.attribute1的属性列表里 navigate(obj, ['attribute1', 'attribute3']);
不过上面的方法返回类型是unknown,不够优雅。我们可以再写一个递归类型,用来推导路径对应的最终值类型:
// 根据路径推导最终值的类型 type PathValue<T, P extends NestedKeyPath<T>> = P extends [infer K, ...infer Rest] ? K extends keyof T ? Rest extends NestedKeyPath<T[K]> ? PathValue<T[K], Rest> : T[K] : never : T;
然后修改泛型方法,让它能自动推导返回值类型:
function navigate<T, P extends NestedKeyPath<T>>(instance: T, arrayAttr: P): PathValue<T, P> { let current: any = instance; for (const attr of arrayAttr) { current = current[attr]; } return current; }
现在再调用的话,result的类型会被正确推导成string,完全符合预期:
const result = navigate(obj, ['attribute1', 'attribute2', 'attribute3']); // result 的类型是 string,不是 unknown
最后补充个小提示:如果你的对象里有可选属性、或者属性值可能是null/undefined,可以调整递归类型来处理这些边界情况,比如在NestedKeyPath里过滤掉可选属性,或者在PathValue里处理null的类型分支。
备注:内容来源于stack exchange,提问作者pokeRex110
相关产品推荐
相关产品推荐

