我正在构建一个自定义事件发射器,它接受描述可能事件的文字字符串类型作为通用类型来构建事件 -> 回调映射。当然我可以使用内置地图,但是来吧...
我想使用 [] 符号来更改列出的事件的键
我从这样的事情开始:
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) 很容易创建与某些 API 响应匹配的泛型类型。
我很惊讶这行得通。当你定义它时,我真的无法弄清楚 [] 里面的语法是什么。
对此有什么想法吗?
答案 0 :(得分:0)
首先,如果您需要将 callback
添加到 events 数组,您应该将其键入为 FunctionDescriptor
,因为这正是您在这里所期望的。
为了将 smth 添加到事件数组中,您需要确保 event
中存在 this.prop
属性
这是一个例子:
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)
}
}
}
Here,在我的博客中,您可以找到有关输入事件的更多信息