Files
query/docs/json-schema-inference.md

4.3 KiB
Raw Permalink Blame History

JSON Schema 类型推断优化说明

问题描述

之前在使用 createQueryApi 时,如果 API 定义使用 JSON Schema而不是 Zod schema参数类型会被推断为 unknown,导致失去类型安全性。

优化方案

修改内容

src/query-api.ts 中增强了 InferFromJSONSchemaInferType 类型,使其能够正确处理:

  1. 嵌套对象的 JSON Schema
  2. 带有 $schema 字段的 JSON Schema
  3. 没有 type 字段但有 properties 字段的对象

核心改进

// 增强的 InferFromJSONSchema 类型
type InferFromJSONSchema<T> =
  // ... 基础类型处理 ...
  // 新增:处理没有 type 但有 properties 的对象
  T extends Record<string, any>
  ? T extends { properties: infer P }
    ? { [K in keyof P]: InferFromJSONSchema<P[K]> }
    : unknown
  : unknown;

// 增强的 InferType 类型
type InferType<T> =
  T extends z.ZodType<infer U> ? U :
  T extends { type: infer TType } ? InferFromJSONSchema<T> :
  T extends { properties: infer P } ? InferFromJSONSchema<T> : // 新增
  T;

使用示例

示例 1: 基础 JSON Schema

const api = {
  "user": {
    "get": {
      "path": "user",
      "key": "get",
      "metadata": {
        "args": {
          "userId": { "type": "string" },
          "includeProfile": { "type": "boolean" }
        }
      }
    }
  }
} as const;

const queryApi = createQueryApi({ api });

// ✅ 完整的类型推断
queryApi.user.get({
  userId: '123',          // string
  includeProfile: true    // boolean
});

示例 2: 嵌套对象(你的场景)

const api = {
  "app_domain_manager": {
    "get": {
      "path": "app_domain_manager",
      "key": "get",
      "metadata": {
        "args": {
          "data": {
            "$schema": "https://json-schema.org/draft/2020-12/schema",
            "type": "object",
            "properties": {
              "id": { "type": "string" },
              "domain": { "type": "string" }
            }
          }
        }
      }
    }
  }
} as const;

const queryApi = createQueryApi({ api });

// ✅ data 参数被正确推断为 { id: string, domain: string }
queryApi.app_domain_manager.get({
  data: {
    id: '123',
    domain: 'example.com'
  }
});

示例 3: 枚举类型

const api = {
  "order": {
    "updateStatus": {
      "metadata": {
        "args": {
          "status": {
            "type": "string",
            "enum": ["pending", "processing", "shipped"] as const
          }
        }
      }
    }
  }
} as const;

const queryApi = createQueryApi({ api });

// ✅ status 被推断为 "pending" | "processing" | "shipped"
queryApi.order.updateStatus({
  status: 'shipped'  // 自动补全和类型检查
});

示例 4: 复杂嵌套

const api = {
  "product": {
    "create": {
      "metadata": {
        "args": {
          "product": {
            "type": "object",
            "properties": {
              "name": { "type": "string" },
              "price": { "type": "number" },
              "tags": {
                "type": "array",
                "items": { "type": "string" }
              },
              "metadata": {
                "type": "object",
                "properties": {
                  "color": { "type": "string" }
                }
              }
            }
          }
        }
      }
    }
  }
} as const;

const queryApi = createQueryApi({ api });

// ✅ 深度嵌套的类型推断
queryApi.product.create({
  product: {
    name: 'T-Shirt',      // string
    price: 29.99,         // number
    tags: ['summer'],     // string[]
    metadata: {
      color: 'blue'       // string
    }
  }
});

支持的 JSON Schema 特性

  • 基础类型: string, number, integer, boolean
  • 对象类型: type: "object" with properties
  • 数组类型: type: "array" with items
  • 枚举类型: enum 字段
  • 嵌套对象和数组
  • 忽略 $schema 等元数据字段
  • 支持 as const 断言以获得更精确的类型

类型安全

优化后TypeScript 会:

  • 提供完整的自动补全
  • 在编译时检测类型错误
  • 防止传入不存在的属性
  • 确保值的类型正确

测试

运行测试文件验证类型推断:

bun test/json-schema-examples.ts