TypeScript不支持AJV const校验的$data选项问题求助
AJV校验密码一致性:$data引用TypeScript报错及解决
问题场景
想用AJV的$data引用功能校验请求体中password与confirmPassword字段是否相等,但TypeScript抛出类型错误:
Types of property 'const' are incompatible. Type '{ $data: string; }' is not assignable to type 'string'.
尝试过两种方案:一种仅屏蔽类型错误但AJV编译时忽略const校验,另一种无效果;还自定义了matchPassword关键字,同样未解决问题。
相关代码
自定义关键字代码
ajv.addKeyword({ keyword: "matchPassword", type: "string", schemaType: "boolean", // FIXME: 不要使用any类型 validate: (schema: any, data: any, parentSchema: any, parentData: any): any => { return schema ? parentData.password === data : true; }, errors: false }) ... const userSchema: JSONSchemaType<User> = { type: "object", properties: { /* 注:"username"是自定义格式,详见../validates */ username: { type: "string", format: "username" }, email: { type: "string", format: "email" }, password: { type: "string", minLength: 5, maxLength: 256 }, confirmPassword: { type: "string", passwordMatch: true // 关键字名拼写错误! }, }, ...
userSchema.ts代码
import { JSONSchemaType } from "ajv"; interface User { username: string; email: string; password: string; confirmPassword: string; } const userSchema: JSONSchemaType<User> = { type: "object", properties: { /* 注:"username"是自定义格式,详见../validates */ username: { type: "string", format: "username" }, email: { type: "string", format: "email" }, password: { type: "string", minLength: 5, maxLength: 256 }, confirmPassword: { type: "string", const: { $data: "1/password" } }, }, required: ["username", "email", "password", "confirmPassword"], additionalProperties: false, errorMessage: { properties: { username: "用户名长度需为5-10位,仅允许包含字母、数字和下划线", password: "密码长度不能少于5位", confirmPassword: "两次输入的密码不一致", }, }, }; export default userSchema;
解决方法
方法一:修复$data引用的类型兼容与AJV配置
- 启用AJV的$data支持:创建AJV实例时必须添加
data: true选项,否则$data引用会被直接忽略:
import Ajv from "ajv"; const ajv = new Ajv({ data: true }); // 关键配置
- 扩展AJV类型以支持$data:通过类型声明合并,让
JSONSchemaType的const字段兼容$data对象:
declare module "ajv" { interface JSONSchemaType<T> { const?: T | { $data: string }; } }
完成后即可直接在schema中使用const: { $data: "1/password" },无需额外类型断言。
方法二:正确实现自定义关键字
之前的自定义关键字存在两处错误:关键字名拼写不一致(定义了matchPassword但用了passwordMatch)、schemaType设计不合理。修正后的实现:
- 定义自定义关键字:
ajv.addKeyword({ keyword: "matchPassword", type: "string", schemaType: "string", // 用字符串指定要匹配的目标字段名 validate: (targetField: string, data: string, _, parentData) => { return parentData?.[targetField] === data; }, errors: true, errorMessage: "两次输入的密码不一致" });
- 在schema中使用:
const userSchema: JSONSchemaType<User> = { // ...其他配置 properties: { // ...其他字段 confirmPassword: { type: "string", matchPassword: "password" // 指定匹配的字段为password }, }, // ...其他配置 };
以上两种方法均可解决类型错误,同时实现密码一致性校验。
内容的提问来源于stack exchange,提问作者lubegasimon
相关产品推荐
相关产品推荐

