如何声明条件存在的属性?TypeScript条件属性类型定义
如何定义TypeScript类型,让data仅在code为200时存在?
我的服务器返回的数据结构如下:
{ code: number; info: string; data //仅在code为200时存在 }
我编写了如下代码处理返回结果:
const res = await fetch(...) const result:MyType = await res.json() if (result.code != 200) { //处理无data的情况 } else { //处理result.data }
GitHub Copilot给出了一种实现方案,看起来可行,但我想了解是否有其他实现方式:
type Type1 = { code: number; info: string; data?: string; // 可选属性 } type Type2 = Type1 & { code: 200, data: string }; // 使用示例: const obj1: Type2 = { code: 200, info: "Success" }; // 报错:缺少data属性,但可以将obj1定义为Type1 const obj2: Type1 = { code: 404, info: "Not Found" }; // 合法 const obj3: Type2 = { code: 200, info: "Success", data: "Some data" }; // 合法
其他可行的实现方式
1. 直接使用判别式联合类型(最推荐)
这是TypeScript中处理这类"条件存在属性"场景最直观的方式,通过联合两个明确的类型,让TypeScript能根据code的值自动推断属性是否存在:
// 定义成功响应类型,code固定为200且必须有data type SuccessResponse = { code: 200; info: string; data: string; // 这里可以换成你实际的data类型,比如unknown/自定义类型 }; // 定义失败/其他响应类型,code为非200,没有data type ErrorResponse = { code: Exclude<number, 200>; info: string; }; // 联合类型作为最终的响应类型 type ApiResponse = SuccessResponse | ErrorResponse; // 使用示例 const res = await fetch(...); const result: ApiResponse = await res.json(); if (result.code === 200) { // TypeScript会自动推断这里result是SuccessResponse,可直接访问result.data console.log(result.data); } else { // 这里result是ErrorResponse,不存在data属性 console.log(result.info); }
这种方式的优势是类型检查最严格:如果code是200,TypeScript会强制要求存在data;如果code不是200,就完全不能访问data,避免了可选属性可能带来的undefined风险。
2. 利用条件类型实现
通过条件类型可以动态根据code的值决定类型结构,适合需要复用类型逻辑的场景:
type ApiResponse<TCode extends number> = TCode extends 200 ? { code: 200; info: string; data: string } : { code: TCode; info: string }; // 使用示例 // 当明确code为200时 const successRes: ApiResponse<200> = { code: 200, info: "ok", data: "data" }; // 当code为其他值时 const errorRes: ApiResponse<404> = { code: 404, info: "not found" }; // 对于未知code的情况,可以结合联合类型 type UnknownApiResponse = ApiResponse<200> | ApiResponse<Exclude<number, 200>>; const result: UnknownApiResponse = await res.json(); if (result.code === 200) { console.log(result.data); }
3. 改进Copilot的方案
Copilot的方案使用了交叉类型,但可以优化得更严格:把基础类型中的code改为非200的数值,避免出现code=200却没有data的合法情况:
type ErrorResponse = { code: Exclude<number, 200>; info: string; data?: never; // 明确禁止非200响应出现data }; type SuccessResponse = { code: 200; info: string; data: string; }; type ApiResponse = ErrorResponse | SuccessResponse;
这样修改后,非200的响应即使写了data也会报错,进一步强化了类型约束。
内容的提问来源于stack exchange,提问作者Qiulang
相关产品推荐
相关产品推荐

