TypeScript中如何实现嵌套键索引并定义Validation的$validations类型
让我帮你一步步解决这两个TypeScript类型的问题,先从ProxyNestedKeys开始,再处理Validation类型的需求~
修复ProxyNestedKeys类型
你原来的代码存在语法错误——映射类型里不能同时写两个in语句。根据你“可通过O的嵌套属性索引”的需求,我提供两种常见实现方案,你可以根据实际场景选择:
方案1:扁平路径键(如"foo.bar")
如果需要生成以嵌套属性路径字符串为键的对象类型(比如可以通过ProxyNestedKeys<O>["foo.bar"]访问),可以用TypeScript的模板字符串类型拼接路径:
// 仅支持一层嵌套的ProxyNestedKeys type ProxyNestedKeys<O extends Record<string, object>> = { [P in keyof O as `${Extract<P, string>}.${Extract<keyof O[P], string>}`]: boolean; };
举个测试例子:
type TestObj = { foo: { bar: number; baz: string }; qux: { quux: boolean }; }; type NestedKeys = ProxyNestedKeys<TestObj>; // 最终类型等价于: // { "foo.bar": boolean; "foo.baz": boolean; "qux.quux": boolean }
方案2:嵌套对象结构
如果需要生成和原对象结构一致的嵌套对象(键层级和原对象对应),写法更简单:
type ProxyNestedKeys<O> = { [P in keyof O]: { [Q in keyof O[P]]: boolean; }; };
对应上面的TestObj,生成的类型是:
{ foo: { bar: boolean; baz: boolean }; qux: { quux: boolean }; }
实现仅支持一层嵌套的Validation类型
根据你的示例,我们需要去掉递归逻辑,只处理一级嵌套的字段。先定义一个辅助类型描述单个嵌套字段的验证结果,再构建主类型:
步骤1:定义嵌套字段的验证结果结构
// 描述单个嵌套字段的验证结果:包含整体有效性和各规则的结果 type NestedValidationResult<Rules> = { $isValid: boolean; $validations: { [Rule in keyof Rules]: boolean }; };
步骤2:构建主Validation类型
用条件类型判断当前schema字段是否为嵌套对象,返回对应的结构(非嵌套字段可根据需求调整,这里默认返回布尔值):
// S为state类型,V为schema类型,仅支持一层嵌套 type Validation<State, Schema> = { [K in Extract<keyof State, keyof Schema>]: // 判断当前schema字段是否是嵌套的验证规则对象 Schema[K] extends Record<string, unknown> ? NestedValidationResult<Schema[K]> : boolean; // 非嵌套字段直接返回布尔值,可按需修改 };
测试你的示例
用你给出的schema和state测试类型推导:
const schema = { foo: { minVal: 2, maxVal: 5 } } as const; const state = { foo: 6 } as const; type ValidationResult = Validation<typeof state, typeof schema>; // 最终类型等价于: // { // foo: { // $isValid: boolean; // $validations: { minVal: boolean; maxVal: boolean }; // }; // }
这个类型完全匹配你期望的验证结果结构。如果你需要全局的验证状态(比如整个表单是否有效),可以给类型加上交叉扩展:
type Validation<State, Schema> = { [K in Extract<keyof State, keyof Schema>]: Schema[K] extends Record<string, unknown> ? NestedValidationResult<Schema[K]> : boolean; } & { $isValid: boolean; // 全局验证是否通过 };
内容的提问来源于stack exchange,提问作者Adrian Adkison
相关产品推荐
相关产品推荐

