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
相关产品推荐
相关产品推荐

