繁体   English   中英

基于 TypeScript 中具有区分联合的其他参数推断 function 参数的类型

[英]Infering type of function argument based on other argument with discriminated union in TypeScript

我有一个描述事件类型的有区别的联合。 然后我有addEventHandler function ,它将事件 ID 作为第一个参数,将事件回调作为第二个参数。 事件 ID 字段是联合类型的鉴别器。

interface TestEventA {
  id: 'TestEventA';
  payload: null;
}

interface TestEventB {
  id: 'TestEventB';
  payload: TestEventBPayload;
}
interface TestEventBPayload {
  content: string;
}

interface TestEventC {
  id: 'TestEventC';
  payload: TestEventCPayload;
}
interface TestEventCPayload {
  value: number;
}

type TestEvent = (TestEventA | TestEventB | TestEventC);

function addEventHandler<T extends TestEvent['id']>(eventId: T, listener: (data: (TestEvent & { id: T })) => void) {
  eventEmitter.on(eventId, listener);
}


addEventHandler('TestEventC', (event) => {
  // I want event to be of type TestEventC, but instead it is of type
  // (TestEventA & { id: "TestEventC"; }) | (TestEventB & { id: "TestEventC"; }) | (TestEventC & { id: "TestEventC"; })

  // event.payload: Object is possibly 'null'
  // Property 'value' does not exist on type 'TestEventBPayload | TestEventCPayload'
  console.log(event.payload.value);

  if (event.id === 'TestEventC') { // redundant condition
    console.log(event.payload.value); // No error here
  }
});

如何使addEventHandler回调 function 推断事件的类型?

作为一种解决方法,您可以创建一个将事件 ID 映射到有效负载的接口,例如:

interface TestEventBPayload {
  content: string;
}

interface TestEventCPayload {
  value: number;
}

interface Events {
  TestEventA: null,
  TestEventB: TestEventBPayload,
  TestEventC: TestEventCPayload
};

function addEventHandler<TId extends keyof Events>(
  eventId: TId,
  listener: (data: Events[TId] & { id: TId }) => void
): void {
  eventEmitter.on(eventId, listener);
}

addEventHandler('TestEventC', (event) => {
  console.log(event.value);

  if (event.id === 'TestEventC') {
    console.log(event.value);
  }
});

操场

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM