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

TypeScript如何转换API事件数组为混合类型列表并实现UI条件渲染?

1. 转换原始事件列表为混合类型列表

首先定义区分联合类型(Discriminated Union),利用type字段作为类型区分标志:

// 先定义事件类型枚举
enum EventType_Enum {
  Type1 = 'type1',
  Type2 = 'type2'
}

// 各类型事件接口
interface EventType1 {
  id: string
  timestamp: Date
  type: EventType_Enum.Type1
  typeField1: number
  typeField2: string
}

interface EventType2 {
  id: string
  timestamp: Date
  type: EventType_Enum.Type2
  typeFieldA: boolean
  typeFieldB: string[]
}

// 联合类型统一所有事件类型
type TypedEvent = EventType1 | EventType2

接下来编写转换函数,通过类型守卫确保类型安全:

// 类型守卫:校验是否为EventType1
function isEventType1(event: any): event is EventType1 {
  return event.type === EventType_Enum.Type1 && typeof (event as EventType1).typeField1 === 'number'
}

// 类型守卫:校验是否为EventType2
function isEventType2(event: any): event is EventType2 {
  return event.type === EventType_Enum.Type2 && typeof (event as EventType2).typeFieldA === 'boolean'
}

// 转换单个原始事件
function transformEvent(rawEvent: Event): TypedEvent {
  const parsedPayload = JSON.parse(rawEvent.payload)
  const baseProps = {
    id: rawEvent.id,
    timestamp: rawEvent.timestamp,
    type: rawEvent.type
  }

  switch (rawEvent.type) {
    case EventType_Enum.Type1:
      const type1Event = { ...baseProps, ...parsedPayload } as EventType1
      if (!isEventType1(type1Event)) {
        throw new Error(`EventType1 payload格式错误: ${rawEvent.payload}`)
      }
      return type1Event
    case EventType_Enum.Type2:
      const type2Event = { ...baseProps, ...parsedPayload } as EventType2
      if (!isEventType2(type2Event)) {
        throw new Error(`EventType2 payload格式错误: ${rawEvent.payload}`)
      }
      return type2Event
    default:
      throw new Error(`不支持的事件类型: ${rawEvent.type}`)
  }
}

// 转换整个事件列表
function transformEvents(rawEvents: Event[]): TypedEvent[] {
  return rawEvents.map(transformEvent)
}

2. UI条件渲染与自定义方法实现

方式一:基于类型分支的条件渲染

在UI组件中(以React为例),直接通过type字段做分支判断:

function EventList({ events }: { events: TypedEvent[] }) {
  return (
    <div className="event-list">
      {events.map(event => {
        switch (event.type) {
          case EventType_Enum.Type1:
            return (
              <div key={event.id} className="event-type1">
                <h3>类型1事件</h3>
                <p>字段1:{event.typeField1}</p>
                <p>字段2:{event.typeField2}</p>
              </div>
            )
          case EventType_Enum.Type2:
            return (
              <div key={event.id} className="event-type2">
                <h3>类型2事件</h3>
                <p>字段A:{event.typeFieldA ? '是' : '否'}</p>
                <p>字段B:{event.typeFieldB.join(', ')}</p>
              </div>
            )
          default:
            return null
        }
      })}
    </div>
  )
}

方式二:用类实现带render方法的事件

TypeScript接口仅能定义方法签名,无法实现逻辑。如果想让事件自身具备渲染能力,可以用类来实现:

// 抽象基类,定义通用属性和抽象渲染方法
abstract class BaseEvent {
  id: string
  timestamp: Date
  type: EventType_Enum

  constructor(id: string, timestamp: Date, type: EventType_Enum) {
    this.id = id
    this.timestamp = timestamp
    this.type = type
  }

  abstract render(): JSX.Element
}

// Type1事件类,实现渲染逻辑
class EventType1Class extends BaseEvent {
  typeField1: number
  typeField2: string

  constructor(rawEvent: Event, payload: { typeField1: number; typeField2: string }) {
    super(rawEvent.id, rawEvent.timestamp, EventType_Enum.Type1)
    this.typeField1 = payload.typeField1
    this.typeField2 = payload.typeField2
  }

  render(): JSX.Element {
    return (
      <div key={this.id} className="event-type1">
        <h3>类型1事件</h3>
        <p>字段1:{this.typeField1}</p>
        <p>字段2:{this.typeField2}</p>
      </div>
    )
  }
}

// Type2事件类,实现渲染逻辑
class EventType2Class extends BaseEvent {
  typeFieldA: boolean
  typeFieldB: string[]

  constructor(rawEvent: Event, payload: { typeFieldA: boolean; typeFieldB: string[] }) {
    super(rawEvent.id, rawEvent.timestamp, EventType_Enum.Type2)
    this.typeFieldA = payload.typeFieldA
    this.typeFieldB = payload.typeFieldB
  }

  render(): JSX.Element {
    return (
      <div key={this.id} className="event-type2">
        <h3>类型2事件</h3>
        <p>字段A:{this.typeFieldA ? '是' : '否'}</p>
        <p>字段B:{this.typeFieldB.join(', ')}</p>
      </div>
    )
  }
}

// 转换函数调整为返回类实例
function transformEventToClass(rawEvent: Event): BaseEvent {
  const parsedPayload = JSON.parse(rawEvent.payload)
  switch (rawEvent.type) {
    case EventType_Enum.Type1:
      return new EventType1Class(rawEvent, parsedPayload)
    case EventType_Enum.Type2:
      return new EventType2Class(rawEvent, parsedPayload)
    default:
      throw new Error(`不支持的事件类型: ${rawEvent.type}`)
  }
}

// UI组件中直接调用render方法
function EventListWithClasses({ events }: { events: BaseEvent[] }) {
  return (
    <div className="event-list">
      {events.map(event => event.render())}
    </div>
  )
}

这种方式将渲染逻辑与事件数据绑定,适合复杂场景,但会增加类的维护成本。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:41:18