# Query API 类型推断优化 - 支持 JSON Schema Required 字段 ## 问题描述 之前的 `query-api` 实现对所有参数使用 `Partial`,导致即使 JSON Schema 中定义了 `required` 字段,TypeScript 类型推断也会将所有字段标记为可选。 示例: ```typescript const api = { update: { metadata: { args: { data: { type: "object", properties: { id: { type: "string" }, domain: { type: "string" } }, required: ["domain"] // 只有 domain 是必需的 } } } } } as const; // 之前:所有字段都是可选的 // queryApi.update({ data: {} }) // 不会报错,但应该要求 domain // 现在:正确识别必需字段 queryApi.update({ data: {} }) // 报错:缺少必需字段 "domain" queryApi.update({ data: { domain: "test.com" } }) // 正确 ``` ## 解决方案 ### 1. 增强 `InferFromJSONSchema` 类型 更新类型推断逻辑以支持 `required` 字段: ```typescript type InferFromJSONSchema = // ... 其他类型处理 ... // 对象类型 - 带 required 字段(必需字段 + 可选字段) T extends { type: "object"; properties: infer P; required: infer R extends readonly string[] } ? { // 必需字段 [K in keyof P as K extends R[number] ? K : never]: InferFromJSONSchema } & { // 可选字段 [K in keyof P as K extends R[number] ? never : K]?: InferFromJSONSchema } : // 对象类型 - 不带 required 字段(所有字段可选) T extends { type: "object"; properties: infer P } ? { [K in keyof P]?: InferFromJSONSchema } : ... ``` ### 2. 移除不必要的 `Partial` 从以下位置移除 `Partial` 包装: - `ApiMethods` 类型定义 - `QueryApi.post()` 方法 - `createApi()` 方法内部 ### 3. 支持 additionalProperties 添加对动态对象的支持: ```typescript // 对象类型 - additionalProperties T extends { type: "object"; additionalProperties: infer A } ? (A extends {} ? Record : never) : ... ``` ## 类型推断示例 ### 示例 1:必需字段和可选字段 ```typescript const api = { update: { metadata: { args: { data: { type: "object", properties: { id: { type: "string" }, domain: { type: "string" }, status: { type: "string", enum: ["active", "inactive"] } }, required: ["domain"] } } } } } as const; const queryApi = createQueryApi({ api }); // ✅ 正确:只传必需字段 queryApi.update({ data: { domain: "test.com" } }); // ✅ 正确:传必需字段 + 可选字段 queryApi.update({ data: { domain: "test.com", id: "123", status: "active" } }); // ❌ 错误:缺少必需字段 queryApi.update({ data: { id: "123" } }); // Error: 类型 "{ id: string; }" 中缺少属性 "domain" // ❌ 错误:enum 值不正确 queryApi.update({ data: { domain: "test.com", status: "pending" } }); // Error: 不能将类型 "pending" 分配给类型 "active" | "inactive" ``` ### 示例 2:没有 required 字段(全部可选) ```typescript const api = { list: { metadata: { args: { data: { type: "object", properties: { page: { type: "number" }, pageSize: { type: "number" } } // 没有 required 字段 } } } } } as const; const queryApi = createQueryApi({ api }); // ✅ 所有字段都是可选的 queryApi.list({ data: {} }); queryApi.list({ data: { page: 1 } }); queryApi.list({ data: { page: 1, pageSize: 20 } }); ``` ### 示例 3:动态对象 (additionalProperties) ```typescript const api = { createMeta: { metadata: { args: { metadata: { type: "object", additionalProperties: {} // 动态键值对 } } } } } as const; const queryApi = createQueryApi({ api }); // ✅ 可以传入任意键值对 queryApi.createMeta({ metadata: { key1: "value1", key2: 123 } }); ``` ## 测试 运行测试文件验证类型推断: ```bash npx tsc --noEmit test/verify-fix.ts ``` ## 文件修改 - `src/query-api.ts` - 更新类型推断逻辑 - `test/verify-fix.ts` - 测试用例 - `test/type-test.ts` - 类型推断测试 - `test/debug-type.ts` - 调试类型推断 ## 注意事项 1. **as const** - API 定义必须使用 `as const` 以保持字面量类型 2. **readonly** - 类型推断需要处理 `readonly` 修饰符 3. **enum** - 自动推断 enum 值并提供类型约束 4. **构建** - 修改后需要重新构建项目:`npm run build`