gpt4 book ai didi

javascript - 在使用 Flow 扩展 EventEmitter 的类中限制 `eventName` 的类型?

转载 作者:数据小太阳 更新时间:2023-10-29 03:55:26 25 4
gpt4 key购买 nike

举个例子,假设我有一个类只发出三种可能的事件——'pending''success''failure'。此外,eventHandler 中接收到的参数类型取决于发出的事件 –

  • 如果 'pending'eventHandler 不接收任何参数
  • 如果“成功”eventHandler 收到一个number
  • 如果“失败”eventHandler 收到一个错误

这是我尝试建模的方式:

// @flow

import EventEmitter from 'events'

type CustomEventObj = {|
pending: void,
success: number,
error: Error
|}

declare class MyEventEmitter extends EventEmitter {
on<K: $Keys<CustomEventObj>>(
eventName: K,
eventHandler: (
e: $ElementType<CustomEventObj, K>,
...args: Array<any>
) => void
): this
}

但是,这会导致如下错误:

Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ test.js:12:3

Cannot extend EventEmitter [1] with MyEventEmitter because an indexer property is missing in CustomEventObj [2] in the
first argument of property on.

[1] 3│ import EventEmitter from 'events'
:
8│ error: Error
9│ |}
10│
11│ declare class MyEventEmitter extends EventEmitter {
[2] 12│ on<K: $Keys<CustomEventObj>>(
13│ eventName: K,
14│ eventHandler: (
15│ e: $ElementType<CustomEventObj, K>,
16│ ...args: Array<any>
17│ ) => void
18│ ): this
19│ }
20│

我不想在 CustomEventObj 上有一个索引器属性,因为这不会扼杀只有 3 个可能事件的意义吗?

如有任何帮助,我们将不胜感激。

最佳答案

好吧,我有好消息和坏消息。好消息是,您将能够让 Flow 了解作为参数传递给 on 处理程序的内容。坏消息是,您将无法告诉 Flow 不允许发生您想要的事件之外的其他事件。

因为您要扩展 EventEmitter 类,所以您明确声明您的类将执行与 EventEmitter 相同的操作。因此,由于 EventEmitter 的 on 处理程序将接受任何 string,因此您的“MyEventEmitter”也必须接受 on 处理程序中的任何字符串。即使您只是在收到意外字符串时抛出错误,Flow 仍然希望您遵守该约定。

现在有个好消息:您可以让 Flow 知道您希望在某些事件上收到什么样的参数。诀窍是指定 on 处理程序的多个声明,如下所示:

// @flow

import EventEmitter from 'events'

type CustomEventObj = {|
pending: void,
success: number,
error: Error
|}

declare class MyEventEmitter extends EventEmitter {
on(
'pending',
// Alternatively, you can pass in a callback like () => void
// as the type here. Either works for the examples below.
(
e: null,
...args: Array<any>
) => void
): this;

on(
'success',
(
e: number,
...args: Array<any>
) => void
): this;

on(
'error',
(
e: Error,
...args: Array<any>
) => void
): this;

// Just to satisfy inheritance requirements, but this should
// throw at runtime.
on(
string,
(
e: mixed,
...args: Array<any>
) => void
): this;
}

let myInstance = new MyEventEmitter()

myInstance.on('pending', () => {}) // works
myInstance.on('success', (num: number) => {console.log(num * 2)}) // works
myInstance.on('success', (badStr: string) => {console.log(badStr.length)}) // Error

现在流程明白,如果事件是“成功”,那么回调应该接受一个数字(或一些包含数字的联合类型,如 string | numberany)。

如果您希望 Flow 允许您传递特定事件,那么您将无法从 EventEmitter 类继承。 (推理是这样的:如果您将 MyEventEmitter 传递给一些传递其他事件的外部代码怎么办?Flow 无法阻止这种情况的发生,并且外部代码也无法知道它无法传递除了“待定”、“成功”或“失败”之外的事件)

我已经在 GitHub for trying/reference/forking 上发布了我的代码副本.我会把它贴在 https://flow.org/try/ 上,但我似乎无法理解从 EventEmitter 或 events$EventEmitter 继承。

警告:我认为您可以为函数指定预期参数的原因是因为 events$EventEmitter 的 on 函数具有 handler 参数 declared as Function type .这种类型是 little weird and mostly unchecked .因此,虽然这种在 on 处理程序上进行多次声明的技术适用于现在(Flow 0.69.0),但它可能会与 future 版本的 Flow 或 events$EventsEmitter typedef 一起使用。

关于javascript - 在使用 Flow 扩展 EventEmitter 的类中限制 `eventName` 的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49411515/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com