You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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配置

  1. 启用AJV的$data支持:创建AJV实例时必须添加data: true选项,否则$data引用会被直接忽略:
import Ajv from "ajv";

const ajv = new Ajv({ data: true }); // 关键配置
  1. 扩展AJV类型以支持$data:通过类型声明合并,让JSONSchemaType的const字段兼容$data对象:
declare module "ajv" {
  interface JSONSchemaType<T> {
    const?: T | { $data: string };
  }
}

完成后即可直接在schema中使用const: { $data: "1/password" },无需额外类型断言。

方法二:正确实现自定义关键字

之前的自定义关键字存在两处错误:关键字名拼写不一致(定义了matchPassword但用了passwordMatch)、schemaType设计不合理。修正后的实现:

  1. 定义自定义关键字:
ajv.addKeyword({
  keyword: "matchPassword",
  type: "string",
  schemaType: "string", // 用字符串指定要匹配的目标字段名
  validate: (targetField: string, data: string, _, parentData) => {
    return parentData?.[targetField] === data;
  },
  errors: true,
  errorMessage: "两次输入的密码不一致"
});
  1. 在schema中使用:
const userSchema: JSONSchemaType<User> = {
  // ...其他配置
  properties: {
    // ...其他字段
    confirmPassword: {
      type: "string",
      matchPassword: "password" // 指定匹配的字段为password
    },
  },
  // ...其他配置
};

以上两种方法均可解决类型错误,同时实现密码一致性校验。

内容的提问来源于stack exchange,提问作者lubegasimon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:12:02