我正在创建一个事件发射器。我使用泛型类型将每个事件类型与正确的函数签名相关联。我想将发送到
emit()
的所有参数传输到相应的回调。 TypeScript 将 args[0]
的类型解析为 undefined | something
,但 args[0]
是 undefined
或 something
,而不是 undefined | something
。
这是我的代码:
type NodeEventTypes = "transaction" | "lostSync" | "sync";
type IssuerEventTypes = "tickSize" | "transferRate";
type EventCallbackMap<T extends NodeEventTypes | IssuerEventTypes> = T extends "transaction" ? (tx: string) => void : () => void;
class EventEmitter<EventTypes extends NodeEventTypes | IssuerEventTypes>
{
private eventCallback: { [T in EventTypes]?: Array<EventCallbackMap<T>> };
constructor()
{
this.eventCallback = {};
}
on<T extends EventTypes>(eventType: T, callback: EventCallbackMap<T>): void
{
if (this.eventCallback[eventType] === undefined)
this.eventCallback[eventType] = [];
this.eventCallback[eventType].push(callback);
}
emit<T extends EventTypes>(eventType: T, ...args: Parameters<EventCallbackMap<T>>)
{
if (this.eventCallback[eventType])
this.eventCallback[eventType].forEach(callback => callback(...args));
}
}
错误为
error TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.
,可能是:
error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
Type 'undefined' is not assignable to type 'string'.
this.eventCallback[eventType].forEach(callback => callback(args[0]));
用ai和Google搜索了解决方案,并修改了我项目中的很多行。也尝试过投稿。
问题在于使用条件类型。在您提供真实的事件参数之前,TS 不会推断正确的回调类型,因此条件类型的结果是回调的联合。
Parameters
似乎无法处理这个联盟。
只需使用不同的方法,直接输入参数即可:
type NodeEventTypes = "transaction" | "lostSync" | "sync";
type IssuerEventTypes = "tickSize" | "transferRate";
type EventArgMap = {
[x: string]: [],
} & {transaction: [string]};
type EventCallbackMap<T extends NodeEventTypes | IssuerEventTypes> = (...args: EventArgMap[T]) => void;
class EventEmitter<EventTypes extends NodeEventTypes | IssuerEventTypes>
{
private eventCallback: { [T in EventTypes]?: Array<EventCallbackMap<T>> };
constructor()
{
this.eventCallback = {};
}
on<T extends EventTypes>(eventType: T, callback: EventCallbackMap<T>): void
{
if (this.eventCallback[eventType] === undefined)
this.eventCallback[eventType] = [];
this.eventCallback[eventType].push(callback);
}
emit<T extends EventTypes>(eventType: T, ...args: Parameters<EventCallbackMap<T>>)
{
if (this.eventCallback[eventType])
this.eventCallback[eventType].forEach(callback => callback(...args));
}
}