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

如何基于JSON Schema属性值应用不同子Schema?(AJV+TypeScript)

基于AJV实现依赖于type字段的动态JSON验证(TypeScript + Node.js)

完全可行,AJV原生支持这种基于其他字段值的条件验证,可以通过两种常用方案实现你的需求:

方案1:使用if/then/else关键字

这种方式适合type类型较少的场景,通过判断type字段的值,动态约束fields的结构,同时用additionalProperties: false严格限制仅允许指定字段存在。

示例代码

首先定义AJV schema:

import Ajv from "ajv";

const ajv = new Ajv({ strict: true });

const schema = {
  type: "object",
  required: ["type", "fields"],
  properties: {
    type: { type: "string", enum: ["GPS", "ROOM"] },
    fields: { type: "object" }
  },
  // 当type为GPS时的约束
  if: {
    properties: { type: { const: "GPS" } }
  },
  then: {
    properties: {
      fields: {
        type: "object",
        required: ["lat", "lng"],
        properties: {
          lat: { type: "number" },
          lng: { type: "number" }
        },
        additionalProperties: false // 禁止fields出现其他字段
      }
    }
  },
  // 当type为ROOM时的约束
  else: {
    if: {
      properties: { type: { const: "ROOM" } }
    },
    then: {
      properties: {
        fields: {
          type: "object",
          required: ["temp", "humidity"],
          properties: {
            temp: { type: "number" },
            humidity: { type: "number" }
          },
          additionalProperties: false
        }
      }
    }
  }
};

const validate = ajv.compile(schema);

验证测试:

// 合法的GPS数据
const gpsData = {
  "type": "GPS",
  "fields": {
    "lat": 51.234,
    "lng": -1.5434
  }
};
console.log(validate(gpsData)); // true

// 非法的GPS数据(包含temp字段)
const invalidGpsData = {
  "type": "GPS",
  "fields": {
    "lat": 51.234,
    "lng": -1.5434,
    "temp": 22.5
  }
};
console.log(validate(invalidGpsData)); // false
console.log(validate.errors); // 会提示fields不允许有temp属性

方案2:使用oneOf关键字

当type类型较多时,oneOf会更清晰,每个type对应一个独立的子schema,确保只有其中一个匹配。

示例代码

const schema = {
  type: "object",
  required: ["type", "fields"],
  oneOf: [
    // GPS类型的完整约束
    {
      properties: {
        type: { const: "GPS" },
        fields: {
          type: "object",
          required: ["lat", "lng"],
          properties: {
            lat: { type: "number" },
            lng: { type: "number" }
          },
          additionalProperties: false
        }
      }
    },
    // ROOM类型的完整约束
    {
      properties: {
        type: { const: "ROOM" },
        fields: {
          type: "object",
          required: ["temp", "humidity"],
          properties: {
            temp: { type: "number" },
            humidity: { type: "number" }
          },
          additionalProperties: false
        }
      }
    }
  ]
};

const validate = ajv.compile(schema);

结合TypeScript类型定义

为了让TypeScript类型和AJV验证逻辑对齐,可以使用区分联合类型:

type GpsFields = {
  lat: number;
  lng: number;
};

type RoomFields = {
  temp: number;
  humidity: number;
};

type SensorData = 
  | { type: "GPS"; fields: GpsFields }
  | { type: "ROOM"; fields: RoomFields };

// 使用时会自动根据type推断fields的类型
const processData = (data: SensorData) => {
  if (data.type === "GPS") {
    console.log(data.fields.lat); // TypeScript能识别lat和lng
  } else {
    console.log(data.fields.temp); // TypeScript能识别temp和humidity
  }
};

注意事项

  • 必须设置additionalProperties: false才能严格禁止fields出现未定义的字段;
  • AJV的strict: true模式会启用更严格的校验规则,建议开启;
  • 如果type类型后续会扩展,oneOf方案更容易维护,新增类型只需添加对应的子schema即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 07:20:17