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

198 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# JSON Schema 类型推断优化说明
## 问题描述
之前在使用 `createQueryApi` 时,如果 API 定义使用 JSON Schema而不是 Zod schema参数类型会被推断为 `unknown`,导致失去类型安全性。
## 优化方案
### 修改内容
`src/query-api.ts` 中增强了 `InferFromJSONSchema``InferType` 类型,使其能够正确处理:
1. **嵌套对象的 JSON Schema**
2. **带有 `$schema` 字段的 JSON Schema**
3. **没有 `type` 字段但有 `properties` 字段的对象**
### 核心改进
```typescript
// 增强的 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
```typescript
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: 嵌套对象(你的场景)
```typescript
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: 枚举类型
```typescript
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: 复杂嵌套
```typescript
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 会:
- ✅ 提供完整的自动补全
- ✅ 在编译时检测类型错误
- ✅ 防止传入不存在的属性
- ✅ 确保值的类型正确
## 测试
运行测试文件验证类型推断:
```bash
bun test/json-schema-examples.ts
```