如何借助TypeScript Interface验证输入的JSON数组并生成错误?
如何在运行时基于TypeScript接口验证JSON数组并生成错误信息
TypeScript接口仅存在于编译阶段,编译后会被完全擦除,因此无法通过instanceof这类运行时操作校验类型。我们需要手动编写运行时校验函数,模拟接口的类型规则,同时生成具体的错误信息。
实现思路
- 针对每个接口(如
Address、Employee)编写单独的校验函数,检查字段类型、必填性、枚举值范围; - 校验数组时遍历每个元素,收集所有错误(而非遇到第一个错误就返回);
- 支持检测未知字段(可选,根据需求决定是否允许额外字段);
- 返回包含元素索引和错误描述的结构化错误信息,方便定位问题。
完整校验代码
// 定义错误信息结构 interface ValidationError { index: number; // 数组元素索引(-1表示整体输入错误) message: string; // 具体错误描述 } interface Employee { name: string; age: number; email: string; address?: Address; role?: roleType; } interface Address { city: string; pinCode: number; } type roleType = 'Developer' | 'UI Designer'; // 校验Address对象 function validateAddress(address: any): string | null { if (typeof address !== 'object' || address === null) { return 'address必须是对象类型'; } // 检查必填字段类型 if (typeof address.city !== 'string') { return 'address.city必须是字符串类型'; } if (typeof address.pinCode !== 'number' || !Number.isInteger(address.pinCode)) { return 'address.pinCode必须是整数类型'; } // 检测未知字段(可选,不需要可删除) const allowedAddressKeys = ['city', 'pinCode']; const extraKeys = Object.keys(address).filter(key => !allowedAddressKeys.includes(key)); if (extraKeys.length > 0) { return `address包含未知字段: ${extraKeys.join(', ')}`; } return null; } // 校验Employee对象 const validRoles: roleType[] = ['Developer', 'UI Designer']; function validateEmployee(employee: any): string | null { if (typeof employee !== 'object' || employee === null) { return '必须是对象类型'; } // 检查必填字段 if (typeof employee.name !== 'string') { return 'name必须是字符串类型'; } if (typeof employee.age !== 'number' || !Number.isInteger(employee.age) || employee.age <= 0) { return 'age必须是正整数类型'; } // 简单邮箱格式校验(可根据需求增强正则) const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (typeof employee.email !== 'string' || !emailRegex.test(employee.email)) { return 'email格式不合法'; } // 校验可选的address字段 if (employee.address !== undefined) { const addressError = validateAddress(employee.address); if (addressError) return addressError; } // 校验可选的role字段 if (employee.role !== undefined) { if (!validRoles.includes(employee.role)) { return `role必须是以下值之一: ${validRoles.join(', ')}`; } } // 检测未知字段(可选,不需要可删除) const allowedEmployeeKeys = ['name', 'age', 'email', 'address', 'role']; const extraKeys = Object.keys(employee).filter(key => !allowedEmployeeKeys.includes(key)); if (extraKeys.length > 0) { return `包含未知字段: ${extraKeys.join(', ')}`; } return null; } // 校验整个Employee数组 function validateEmployeeArray(input: any): ValidationError[] { const errors: ValidationError[] = []; // 先检查输入是否为数组 if (!Array.isArray(input)) { errors.push({ index: -1, message: '输入不是合法的JSON数组' }); return errors; } // 遍历每个元素校验 input.forEach((item, index) => { const errorMsg = validateEmployee(item); if (errorMsg) { errors.push({ index, message: `第${index + 1}个元素: ${errorMsg}` }); } }); return errors; }
使用示例(结合textarea输入)
// 从textarea获取输入并解析 const textarea = document.querySelector('textarea'); if (textarea) { const inputValue = textarea.value; try { const parsedData = JSON.parse(inputValue); const validationErrors = validateEmployeeArray(parsedData); if (validationErrors.length === 0) { console.log('所有数据校验通过'); // 断言为Employee[]类型继续业务逻辑 const validEmployees = parsedData as Employee[]; // ...后续处理 } else { console.error('校验失败:', validationErrors); // 将错误展示给用户(示例:输出到控制台) validationErrors.forEach(err => console.error(err.message)); } } catch (e) { console.error('JSON解析失败:', (e as Error).message); } }
关键说明
instanceof失效原因:TypeScript接口仅用于编译时类型检查,编译后的JS代码中不会保留接口定义,因此没有对应的构造函数供instanceof判断;- 可选字段处理:通过判断字段是否为
undefined,再触发对应的子校验; - 枚举类型校验:将
roleType的有效值存入数组,通过includes方法检查输入值是否合法; - 未知字段检测:通过对比允许的字段列表,过滤出多余字段,避免不符合接口的数据流入业务逻辑(不需要可删除该逻辑)。
内容的提问来源于stack exchange,提问作者Shevya
相关产品推荐
相关产品推荐

