ค้นหาเว็บไซต์

javascript - TypeScript - สร้าง Union จากวัตถุ


ฉันกำลังสร้าง EventEmitter ใน TypeScript และฉันไม่สามารถหาวิธีทำสิ่งต่อไปนี้ได้:

สมมติว่าฉันมีอินเทอร์เฟซแบบนี้:

interface EventEmitterSubscription { dispose(): void }

// here it is
interface EventEmitter<T extends { [key: string]: any }> {
  onAnyEvent(callback: (event: { type: ???, payload: ??? }) => void): EventEmitterSubscription
  // ...
}

ฉันไม่สามารถหาวิธีพิมพ์ callback onAnyEvent ได้ เช่น ตัวอย่างเช่น สำหรับ eventEmitter แบบนี้:

EventEmitter<{ onNumberReceived: number, onCatReceived: { cat: ICat }, onPersonNameReceived: string }>

ฟิลด์ onAnyEvent จะมีชนิด

onAnyEvent(callback: (event: { type: 'onNumberReceived', payload: number } | { type: 'onCatReceived', payload: { cat: ICat } } | { type: 'onPersonNameReceived', payload: string }) => void): EventEmitterSubscription

ปัจจุบันการใช้งานของฉันมีอินเทอร์เฟซดูเหมือน:

onAnyEvent(callback: (event: { type: keyof T, payload: T[keyof T] }) => void): EventEmitterSubscription

ยกเว้นว่าปัจจุบันยังใช้ไม่ได้ ตัวอย่างเช่น นั่นจะสร้างประเภท onAnyEvent(callback: (event: { type: 'onNumberReceived', payload: number } | { type: 'onNumberReceived', payload: { cat: ICat } } | /* ... */) => void): EventEmitterSubscription

แล้วฉันจะพิมพ์ฟิลด์ onAnyEvent ได้อย่างไร?

คำตอบ #1

วิธีหนึ่งที่เป็นไปได้ในการสร้าง union คือการมีประเภทแมปที่แต่ละสมบัติมีประเภทเป็นหนึ่งในสมาชิกของ union ที่ต้องการ ดังนี้:

type EventTypeMap<T extends { [key: string]: {} }> =
    { [K in keyof T]: { type: K; payload: T[K] } };

จากนั้นคุณสามารถกำหนดประเภทยูเนียนทั่วไปได้

type CallbackEventTypes<T extends { [key: string]: {} }> =
     EventTypeMap<T>[keyof EventTypeMap<T>] 

และใช้มัน

interface EventEmitterSubscription { dispose(): void }

interface EventEmitter<T extends { [key: string]: {} }> {
  onAnyEvent(callback: (event: CallbackEventTypes<T>) => void): EventEmitterSubscription
  // ...
}

interface ICat { meow() }

type Emitter = EventEmitter<{ onNumberReceived: number, onCatReceived: { cat: ICat }, onPersonNameReceived: string }>

type HandlerType = Emitter['onAnyEvent'];

// inferred as
//type HandlerType = 
// (callback: (event: { type: "onNumberReceived"; payload: number; }
//                  | { type: "onCatReceived"; payload: { cat: ICat; }; }
//                  | { type: "onPersonNameReceived"; payload: string; }
//            ) => void) => EventEmitterSubscription

บทความที่เกี่ยวข้อง