如何实现TypeScript嵌套对象及对象数组的类型安全键校验
实现嵌套对象与数组的表单字段类型安全校验
要实现嵌套对象、数组场景下的name属性与所属键严格匹配的类型安全,核心是通过递归映射类型遍历原Schema的每一层结构,针对性处理基础类型、对象类型和数组类型三种情况。
核心类型定义
// 提取数组的元素类型 type ElementType<T> = T extends (infer U)[] ? U : never; // 递归生成表单结构类型,确保每个name与对应键一致 type FormStructure<T> = { [K in keyof T]: // 处理数组类型:数组元素为对象时,生成TextField数组,name必须匹配元素对象的键 T[K] extends (infer U)[] ? U extends object ? Array<{ name: keyof U; label: string }> : never // 处理对象类型:递归生成嵌套结构,确保键与原Schema一致 : T[K] extends object ? FormStructure<T[K]> // 处理基础类型:生成TextField,name必须等于当前属性键 : { name: K; label: string }; };
完整代码示例
// 原表单Schema定义 type FormSchema = { name: string choices: { choice: string }[] position: { location: { x: number, y: number, z: number } } } // 应用递归类型约束表单结构 const form: FormStructure<FormSchema> = { name: { name: "name", // 必须为"name",否则触发类型报错 label: "Question A" }, choices: [ { name: "choice", // 必须为"choice",否则触发类型报错 label: "Choice" } ], position: { location: { // 必须为"location",否则触发类型报错 x: { name: "x", label: "X" }, // 必须为"x" y: { name: "y", label: "Y" }, // 必须为"y" z: { name: "z", label: "Z" }, // 必须为"z" }, } };
类型校验逻辑说明
- 映射类型遍历:
[K in keyof T]强制表单结构的键与原Schema完全一致,不能新增或遗漏属性。 - 数组处理:提取数组元素类型后,若元素是对象,则要求数组内的每个TextField的
name必须匹配元素对象的键(如示例中choices数组的name必须为"choice")。 - 嵌套对象递归:遇到对象类型时,递归调用
FormStructure,自动处理任意层级的嵌套结构(如position > location > x/y/z的多层校验)。 - 基础类型约束:对于字符串、数字等基础类型,直接约束
name必须等于当前属性的键。
错误场景示例(会触发类型报错)
// 以下代码会被TypeScript拦截,因为不符合类型约束 const badForm: FormStructure<FormSchema> = { name: { name: "wrong", // ❌ 类型不匹配:"wrong"无法赋值为"name" label: "Question A" }, choices: [ { name: "wrong", // ❌ 类型不匹配:"wrong"无法赋值为"choice" label: "Choice" } ], position: { loc: { // ❌ 不存在的属性:"loc"不在原Schema的position结构中 x: { name: "x", label: "X" }, y: { name: "y", label: "Y" }, z: { name: "z", label: "Z" }, }, } };
内容的提问来源于stack exchange,提问作者Re-Angelo
相关产品推荐
相关产品推荐

