当data.type为已知值时,如何为TypeScript对象指定类型?
解决方案:基于可区分联合类型的自动类型推断
你已经定义了可区分联合类型(SmsPayload | EmailPayload),这类类型共享一个用于区分的字段type,TypeScript可以利用这个特性,结合条件判断自动推断具体类型。以下是具体实现方式:
方式一:直接通过字面量判断实现自动类型推断
不需要额外定义工具函数,直接在条件分支中检查type字段的值,TS会自动缩小类型范围:
const payload = '{"type":"sms","destination":123}' type PayloadType = 'sms' | 'email' interface BasePayload { type: PayloadType } interface SmsPayload extends BasePayload { destination: number } interface EmailPayload extends BasePayload { destination: string } // 先将JSON解析结果断言为联合类型 const data = JSON.parse(payload) as SmsPayload | EmailPayload; // 根据type字段自动推断类型 if (data.type === 'sms') { // 此处data被自动推断为SmsPayload,destination是number类型 console.log(data.destination.toFixed(0)); } else { // 此处data被自动推断为EmailPayload,destination是string类型 console.log(data.destination.includes('@')); }
方式二:自定义类型守卫函数(适合复杂场景)
如果需要在多处复用类型判断逻辑,可以定义类型守卫函数,明确告诉TS如何判断某个值属于特定类型:
// 定义类型守卫函数 function isSmsPayload(payload: BasePayload): payload is SmsPayload { return payload.type === 'sms'; } function isEmailPayload(payload: BasePayload): payload is EmailPayload { return payload.type === 'email'; } const rawData = JSON.parse(payload) as BasePayload; if (isSmsPayload(rawData)) { // rawData自动推断为SmsPayload console.log(rawData.destination.toFixed(0)); } else if (isEmailPayload(rawData)) { // rawData自动推断为EmailPayload console.log(rawData.destination.includes('@')); } else { throw new Error(`未知的负载类型: ${rawData.type}`); }
关键说明
- 核心原理是可区分联合类型:因为
SmsPayload和EmailPayload共享type字段,且该字段的取值是互斥的字面量类型,TS可以通过这个字段的值自动缩小类型范围。 JSON.parse默认返回any类型,必须通过类型断言(as SmsPayload | EmailPayload或as BasePayload)告诉TS解析后的对象结构,才能触发后续的类型推断。
内容的提问来源于stack exchange,提问作者Ben Walters
相关产品推荐
相关产品推荐

