具有泛型类型的索引签名断言



我正在构建一个自定义事件发射器,该发射器接受将可能的事件描述为泛型类型的文字字符串类型,以构建事件->回调映射。当然,我可以使用内置的Map,但拜托…

我想使用[]表示法来更改列出的事件的键我从这样的东西开始:

type FunctionDescriptor = {func: Function, args: any[]}
class EventEmitter<Events extends string> {
[k in Events as string]?: FunctionDescriptor[]
somemethods(event: Events) {
this[event] = [...]
}
}

问题是,第一:这不起作用
第二:即使[]签名起作用,我们也需要更改右手边以接受类中需要的所有类型,从而破坏类型检查的全部目的
例如:
let myEventMap = new EventEmitter<MyEvents>(); myEventMap["AnyKey"] = "AnyStuff"
之类的事情是可能的,但这不是我想要的行为
经过一段时间的修补,我想出了这个:

type FunctionDescriptor = {func: Function, args: any[]}
class EventMap<Events> {
protected _: { [k in Events as string]?: FunctionDescriptor[] };
// type asserted method call
add(event: Events, callback: Function) {
// example on how to access it
this._[event].push(callback)
}
}

我对打字很陌生,所以我真的不知道这是否是一个适合我目标的好模式解决方案,但对我来说,它似乎符合我的目标:

a(除了bultin函数之外,不能从外部分配任何东西
b(当您发出或添加事件时,所有事件都经过类型检查
c(很容易创建与ex.的某些API响应匹配的泛型类型。

我对此感到非常惊讶。当你定义[]时,我真的不知道它里面有什么语法。

对此有什么想法吗?

首先,如果您需要将callback添加到事件数组中,您应该将其键入为FunctionDescriptor,因为这正是您在这里所期望的。

为了将smth添加到事件数组中,您需要确保this.prop中存在event属性

这里有一个例子:

type Fn = (...args: any) => any
type FunctionDescriptor = { func: Fn, args: any[] }
type Data<T extends string> = {
[P in T]: FunctionDescriptor[]
}
const isEvent = <T extends string>(prop: Partial<Data<T>>, event: T): prop is Partial<Data<T>> & Record<T, FunctionDescriptor[]> =>
Object.prototype.hasOwnProperty.call(prop, event)
class EventMap<Events extends string> {
protected prop: Partial<Data<Events>> = {};
add(event: Events, callback: FunctionDescriptor) {
if (isEvent(this.prop, event)) {
this.prop[event].push(callback)
}
}
}

游乐场

在这里,在我的博客中,你可以找到更多关于键入事件的信息

最新更新