TypeScript 无法解析正确的类型

问题描述 投票:0回答:1

我正在创建一个事件发射器。我使用泛型类型将每个事件类型与正确的函数签名相关联。我想将发送到

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搜索了解决方案,并修改了我项目中的很多行。也尝试过投稿。

typescript
1个回答
0
投票

问题在于使用条件类型。在您提供真实的事件参数之前,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));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.