簡體   English   中英

獲取 T 型 function 和 T 型 arguments 類型 U 的參數類型

[英]Getting parameter types for function of Type T with arguments type U of T

我正在嘗試鍵入一個事件總線,其中我有一個特定的事件,它具有特定的 arguments。 基本結構是:

connection.on("myEvent", (args) => {});

一個例子可能是

connection.on("OnProductAdded", (productName, id) => console.log(`Product: ${productName} added with id: ${id}));

我在實際事件廣播和消費者之間有一個事件總線類型層,這是我想要類型信息的地方。 我有一個 function 訂閱消費者與回調的特定事件:

function subscribe<T extends keyof EventArgs>(id: string, event: Events, callback: (args: EventHanddlers[T] => void){
    subscriberList.add({id: id, event: event, callback: callback});
}

我將實際事件與以下內容聯系起來:

connection?.on("onProductAdded", (args: EventArgs[OnProductAdded]) => callAllSubscribers(args));

這將在使用代碼時通過以下方式調用:

const { connectionStatus, subscribe } = useEvents();

subscribe<OnProductAdded>("my_consumer_id", (args) => doSomethingOnTheEvent(args));

正是在這里,我想要 OnProductAdded to (productName, id)的參數類型信息。

我已經非常接近但似乎無法使整個循環工作,也許我以錯誤的方式攻擊它或使其過於復雜。 我已經在消費者端顯示了參數,但無法一直編譯類型。 具體來說,當添加類型訂閱者的訂閱時,我會丟失類型信息。 下面的其他類型。

type Subscriber {
    id: string;
    event: Events; // Either OnProductAdded or OnProductDeleted
    callback: EventHandlers; // This goes wrong, because I want to eventhandler to type T.
}

type OnProductAdded = 'OnProductAdded';
type OnProductDeleted = 'OnProductDeleted';

type Events = OnProductAdded | OnProductDeleted;     

type EventArgs = {
    OnProductAdded: { productName: string; id: string; };
    OnProductDeleted: { id: string };
}

type EventHandlers = {
    [P in keyof EventArgs]: (args: Events[P]) => void;
}

上下文的完整非工作在制品代碼:

const useEvents = () => {
    const { connection } = useContext(EventsContext);
    const { array: subscriptions, api: mutateSubscriptions } = useStateArray<Subscriber>([]); // A data structure around arrays to make them nice in react states. The important part is it's Subscriber[];


    //The idea of this function is to find all subscribers who subscribed to event of type T, and call all the callbacks with the parameters received on the event.
    function callAllSubscribers(args: EventHandlers) {
        const eventSubscriberList = subscriptions.filter(x => x.event == event);

        for (const sub of eventSubscriberList) {
            sub.callback(args)

        }

    }

    function subscribe<T extends keyof EventArgs>(id: string, event: Events, callback: EventHandlers[T]) {
        mutateSubscriptions.add({ id, event, callback: callback })
    }

//Wiring all events up. The library fires off events that are bound like normal with .on("eventStringName", (...args) => void);
//My initial idea was to wire them up by looping over all defined events, but currently I could only find a way to do it by manually wiring it up.
connection?.on("onProductAdded", (args: EventArgs[onProductAdded]) => callAllSubscribers(args));

    return { connectionStatus: connection?.state, subscribe };
}

Typescript 是先驅,它不應該依賴於價值。 因此,如果您有預定義事件的列表,您可以嘗試重載 function 聲明:

on(eventName: string, handler: (args: any) => void);
on(eventName: string, handler: (id: string) => void);
on(eventName: string, handler: (productName: string, id: string) => void);

但是,如果您想基於此類值創建類型結構,您可以嘗試類似的方法。 但是我不確定這是否是最佳選擇。

主意:

  • 為事件類型創建類別。
  • 為類別定義接口/類型。
  • on使用這些類型的聯合。 這將定義如果eventName是給定的枚舉,則處理程序將具有此類型。
enum IdBasedEvents {
    PRODUCT_DELETE = 'onProductDelete'
}

enum NameAndIdEvents {
    PRODUCT_ADD = 'onProductAdd'
}

enum GenericEvents {
    MY_EVENT = 'myEvent'
}

type TArgsEvent = (args: any) => void;
type TProductAddEvent = (productName: string, id: string) => void;
type TProductDeleteEvent = (id: string) => void;

type TArgEventHandler =       ( eventName: GenericEvents, handler: TArgsEvent ) => void;
type TProductAddHandler =     ( eventName: NameAndIdEvents, handler: TProductAddEvent ) => void;
type TProductDeleteHandler =  ( eventName: IdBasedEvents, handler: TProductDeleteEvent ) => void;

interface IConnection {
  on: TArgEventHandler | TProductAddHandler | TProductDeleteHandler
}

使用 generics:

type Subscriber<T extends Events> {
    id: string;
    event: T;
    callback: EventHandlers<T>; 
}

type OnProductAdded = 'OnProductAdded';
type OnProductDeleted = 'OnProductDeleted';

type Events = OnProductAdded | OnProductDeleted;     

type EventArgs = {
    OnProductAdded: { productName: string; id: string; };
    OnProductDeleted: { id: string };
}

type EventHandlers<T extends Events> = {
    [T in keyof EventArgs]: (args: T) => void;
}

function /*connection.*/on<T extends Events>(type: T, cb: EventHandlers<T>) {

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM