typescript - 如何强类型化事件发射器,以便从事件类型推断出处理程序的参数类型?

标签 typescript generics typing

我正在尝试定义一个强类型的事件发射器,我最想要的是从传递给 addEventHandler 函数的字符串中推断出回调的事件类型。

但到目前为止我都失败了,我想出的是从回调中推断出事件类型,而不是相反。

这是一个示例(带有 fiddle ):

interface NumberEvent {
  type: 'NumberEvent';
  num: number;
}

interface StringEvent {
  type: 'StringEvent';
  str: string;
}

type AnyEvent = NumberEvent | StringEvent;

const addEventHandler = <ET extends AnyEvent>(type: ET['type'], handler: ((event: ET) => void)) => {
  console.log(`added event handler for ${type}`);
}

addEventHandler('NumberEvent', (event: NumberEvent) => {
  // this is cool
});

addEventHandler('NumberEvent', (event: StringEvent) => {
  // this doesn't type check, good
});

addEventHandler('type does not exist', (x: any) => {
  // why no type error?
});

我不明白为什么最后一行要进行类型检查,因为没有类型为'type does not exist'AnyEvent实例。

你能想出更好的方法来解决这个问题吗?

最佳答案

您可以通过制作 addEventHandler 来实现此目的事件类型的泛型,而不是事件对象。

const addEventHandler = <ET extends AnyEvent['type']>(
  type: ET,
  handler: ((event: Extract<AnyEvent, { type: ET }>) => void)
) => {
  console.log(`added event handler for ${type}`);
}

你也可以使用 AnyEvent & { type: ET }而不是 Extract<AnyEvent & { type: ET }

你的类型没有阻止最后一种情况的原因是因为 ET被推断为 any . any["type"]还是any , 所以它会允许任何字符串。

上面的版本仍然不会阻止某人这样做:

addEventHandler<any>('type does not exist', (x: any) => {
  // explicitly providing <any>
});

您可以使用 <anything> & any 来防止这种情况发生是any ,但就我个人而言,我不会打扰。没有人可能提供 any除非故意破坏你的类型。随着any检查,你也可以回到你的通用:

type NotAny<T> = 0 extends (1 & T) ? never : T; 

const addEventHandler = <ET extends AnyEvent>(type: NotAny<ET["type"]>, handler: ((event: ET) => void)) => {
  console.log(`added event handler for ${type}`);
}

关于typescript - 如何强类型化事件发射器,以便从事件类型推断出处理程序的参数类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70551022/

相关文章:

arrays - 如何从数组<>中删除协议(protocol)

java - 如何在不使用泛型的情况下限制 ArrayList 的元素

java - 为什么泛型数组的声明是正确的?

typescript - 具有动态静态字段的函数

typescript - 为什么这个类型保护在这个三元表达式中不起作用?

class - 在 Angular 2 和 Ionic 2 中访问整个应用程序的关键数据

angular - 何时在 TypeScript/Angular 中使用接口(interface)和模型

arrays - typescript 数组接受错误的类型

python - 递归类型注释

python - __slots__ 与泛型类中的类变量冲突