You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让TypeScript在if语句中识别条件类型

如何让TypeScript根据事件类型自动推断Payload类型

我们定义了条件事件类型,能根据事件类型提示对应的Payload结构:

type EventType = 'created' | 'updated' | 'deleted'
type EventPayload<T> =
  T extends 'created' ? { somethingForCreatedEvent: string } :
  T extends 'updated' ? { somethingForUpdatedEvent: string } :
  T extends 'deleted' ? { somethingForDeletedEvent: string } :
  never

在触发事件的trigger函数里,已经实现了强类型校验:

function trigger<T extends EventType>(type: T, payload: EventPayload<T>) {
  // 发送事件逻辑
}

trigger('created', { somethingForCreatedEvent: "test" }) // 正确提示仅需传入somethingForCreatedEvent
trigger('updated', { somethingForUpdatedEvent: "test" }) // 正确提示仅需传入somethingForUpdatedEvent
trigger('deleted', { somethingForDeletedEvent: "test" }) // 正确提示仅需传入somethingForDeletedEvent

遇到的问题

接收事件时,无法获得对应的强类型支持。接收的事件格式为{ type: EventType; payload: EventPayload<...> },但req.body初始类型为any,即使通过判断type字段,payload仍为any/unknown:

// 从队列接收的事件格式:{ type: EventType; payload: EventPayload<...> }
const eventPayload = req.body // 此时类型为any

if (eventPayload.type === 'created') {
  eventPayload.payload // 类型为any/unknown,无法获得正确提示
}

之前尝试的辅助函数效果不符合预期:

type RawEvent<T> = {
  type: T;
  payload: EventPayload<T>;
}

function getEventPayload<T extends EventType>(rawEvent: any): RawEvent<T> {
  return rawEvent
}

const event = getEventPayload(rawEvent)

if (event.type === 'created') { // type字段能正确提示为'created'
  event.payload // 但payload类型是所有EventPayload的联合类型,而非仅created对应的类型
}

解决方案

要让TypeScript能通过type字段的判断自动收窄payload的类型,需要定义一个联合类型的事件结构,而非泛型的RawEvent<T>:

1. 定义联合事件类型

// 生成所有事件类型的联合类型
type Event = {
  [K in EventType]: {
    type: K;
    payload: EventPayload<K>;
  };
}[EventType];

2. 编写类型守卫函数(推荐)

添加运行时校验的类型守卫,确保输入符合Event类型,同时让TypeScript自动收窄类型:

// 类型守卫函数,判断输入是否为合法的Event类型
function isEvent(raw: any): raw is Event {
  if (!raw || typeof raw !== 'object') return false;
  // 先校验type字段是否为合法的EventType
  if (!(['created', 'updated', 'deleted'] as const).includes(raw.type)) return false;
  // 再根据type校验对应的payload结构
  switch (raw.type) {
    case 'created':
      return typeof raw.payload?.somethingForCreatedEvent === 'string';
    case 'updated':
      return typeof raw.payload?.somethingForUpdatedEvent === 'string';
    case 'deleted':
      return typeof raw.payload?.somethingForDeletedEvent === 'string';
    default:
      return false;
  }
}

3. 使用示例

现在使用时,TypeScript会自动根据type字段收窄payload的类型:

const eventPayload = req.body;

if (isEvent(eventPayload)) {
  if (eventPayload.type === 'created') {
    // 正确提示somethingForCreatedEvent字段
    console.log(eventPayload.payload.somethingForCreatedEvent);
  } else if (eventPayload.type === 'updated') {
    console.log(eventPayload.payload.somethingForUpdatedEvent);
  } else if (eventPayload.type === 'deleted') {
    console.log(eventPayload.payload.somethingForDeletedEvent);
  }
}

简化方案(无运行时校验)

如果不需要运行时校验,可直接使用类型断言,但这种方式跳过了合法性检查,存在风险:

const event = req.body as Event;

if (event.type === 'created') {
  console.log(event.payload.somethingForCreatedEvent); // 类型正确,能获得提示
}

内容的提问来源于stack exchange,提问作者Ollie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 00:46:09