单纯用 t extends u ? x : y 无法推导响应字段,因它只做类型兼容判断而不解析结构;必须结合 infer 提取子类型与分布式条件类型处理联合响应。

直接用 T extends { success: true } ? { data: T } : { error: string } 这类写法,推不出实际数据结构——它只做静态分支判断,不解析响应体字段。真正能自动化推断 API 返回结构的,得靠条件类型 + infer + 分布式行为三者联动。
为什么单纯用 T extends U ? X : Y 无法推导响应字段
条件类型本身不“读取”对象属性,只做类型兼容性判断。比如你传入 { success: true; result: { id: 1 } },T extends { success: true } 为真,但返回的 { data: T } 里 data 类型还是整个原始对象,不是你想要的 { id: 1 }。
常见错误现象:
- 调用后 IDE 提示
data是any或宽泛的联合类型 - 想取
res.data.id,但编译报错“Property 'id' does not exist on type 'T'” - 手动加
as断言才能通过,失去类型安全意义
必须搭配 infer 才能提取嵌套结构
infer 是唯一能从类型中“抓出子类型”的机制。比如要从 { success: true; data: User } 中抽出 User,就得写:
type ExtractData<t> = T extends { success: true; data: infer D } ? D : never;</t>
关键点:
-
infer D必须出现在extends右侧的类型模式中,不能写在问号后面 - 如果结构不完全匹配(比如字段名是
payload而非data),整个条件就走never分支,结果为空联合类型 - 多个
infer可同时使用:T extends { code: 200; body: infer B; meta: infer M }
联合响应格式需依赖分布式条件类型
真实 API 常返回 { code: 200; data: User } | { code: 400; error: string }。这时单层条件类型会失效,因为 TypeScript 默认对联合类型每个成员分别应用条件逻辑(即“分布式行为”)。
正确做法是让条件类型作用于裸泛型参数:
type ApiResponse<t> = T extends { code: 200; data: infer D }
? { ok: true; data: D }
: T extends { code: number; error: infer E }
? { ok: false; error: E }
: never;</t>
这样 ApiResponse 就能自动拆解、分别映射,最终得到 { ok: true; data: User } | { ok: false; error: 'Unauthorized' }。
容易踩的坑:
- 把泛型包进元组或对象(如
[T]或{ input: T })会关闭分布式行为,导致整个联合被当做一个整体处理 - 没写
never终止分支,TypeScript 会补全为unknown,破坏类型收敛 - 字段名大小写/拼写不一致(如
Datavsdata)直接让infer失效
实际封装建议:用工具类型组合而非硬编码
不要为每个接口单独写一遍 ExtractData,而是抽象成可复用的工具:
// 支持自定义成功字段和数据字段
type StandardResponse<t successkey extends keyof t="success" datakey> =
T extends Record<successkey true> & Record<datakey infer d>
? { data: D; error: null }
: T extends Record
? { data: null; error: string }
: never;</datakey></successkey></t>
使用时:
type UserRes = { success: true; data: { id: number; name: string } };
type Result = StandardResponse<userres>; // { data: { id: number; name: string }; error: null }</userres>
注意点:
- 字段名作为泛型参数传入,避免重复定义;但运行时不可变,所以仅适用于约定稳定的响应规范
-
Record<k v></k>比直接写{ [K]: V }更安全,能防止 K 不在 T 中时意外通过 - 这种封装在大型项目中容易失控——一旦后端改一个字段名,所有调用处都会爆红,得同步更新泛型参数
最易被忽略的是:条件类型推导结果不会反向影响运行时数据形状。即使类型上 data 被精确推为 User,如果你实际返回的是 { success: true, data: null },TS 也拦不住——它只校验你写的类型是否自洽,不校验数据是否符合类型。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











