簡體   English   中英

推斷 typescript 中的映射參數類型

[英]Infer a mapped parameter type in typescript

我正在使用一個具有有趣類型聲明(簡化)的庫:

class Emitter {
    public on<EventName extends 'streamCreated' | 'streamDestroyed'> (eventName: EventName, callback: (event: {
        streamCreated: {id: number};
        streamDestroyed: {reason: string};
    }[EventName]) => void): void;
}

我正在嘗試在我提供的回調中鍵入事件:

const callback = (event: StreamDestroyedEvent) => console.log(event.reason);
emitter.on('streamDestroyed', callback);

但是“StreamDestroyedEvent”不存在。 它不是由庫提供的,而是僅存在於該匿名事件映射中,因此我嘗試推斷它:

type InferCallback<T, E> = T extends (eventName: E, event: infer R) => void ? R : never;
type InferCallbackEvent<T, E> = InferCallback<T, E> extends (event: infer P) => void ? P : never;
type StreamDestroyedEvent = InferCallbackEvent<Emitter['on'], 'streamDestroyed'>;

但是,它沒有給我一個{reason: string}類型,而是得到聯合類型{reason: string;} | {id: number;} {reason: string;} | {id: number;} 我怎樣才能得到正確的類型,或者這是否與我將得到的一樣接近?

您基本上想為EventName類型參數“插入”一個類型。 雖然 TypeScript 在調用泛型 function 時支持這一點,但它並不能很好地在類型系統本身中表示此類類型。 這樣做完全需要支持更高級別的類型,這並不是語言的一部分。 emitter.on function 本身並不能真正讓您“部分地”調用它,以便您使用第一個參數插入EventName ,然后讓編譯器告訴第二個參數的類型應該是什么。

在 TypeScript 3.4 出來之前,我可能會說從編譯器中獲取這些信息是不可能的。 我會嘗試類似的東西

emitter.on("streamDestroyed", x => {
  type StreamDestroyedEvent = typeof x; // can't get it out of the scope though!
})

然后無法獲取StreamDestroyedEvent類型以逃避 function。

TypeScript 3.4 引入了改進的泛型函數支持高階類型推斷 你仍然不能純粹在類型系統中表示你在做什么,但現在我們可以定義一個 function ,它為我們提供了一些我們可以做的“部分”調用並保留我們需要的類型信息。

Here is a currying function which takes a multi-argument function and returns a new function of one argument that returns another function of the remaining arguments:

const curry = <T, U extends any[], R>(
  cb: (t: T, ...args: U) => R
) => (t: T) => (...args: U) => cb(t, ...args);

如果您在emitter.on上調用curry ,然后使用"streamDestroyed"調用,(在 TS3.4+ 中)您會得到一個 function ,它需要一個回調,該回調需要一個StreamDestroyedEvent ,您現在可以捕獲:

const streamDestroyedFunc = curry(emitter.on.bind(emitter))("streamDestroyed")
type StreamDestroyedEvent = Parameters<Parameters<typeof streamDestroyedFunc>[0]>[0];
// type StreamDestroyedEvent = { reason: string; }

請注意,上面的實際運行時行為不是重點; 我試圖確保它實際上會做一些合理的事情,但你也可以只使用類型斷言來向編譯器謊報正在發生的事情,只要你在運行它時沒有遇到運行時錯誤:

const fakeCurry: typeof curry = () => () => null!;
const fakeOn: Emitter["on"] = null!;
const fakeFunc = fakeCurry(fakeOn)("streamDestroyed");
type SDE2 = Parameters<Parameters<typeof fakeFunc>[0]>[0]; // same thing

好的,希望有幫助; 祝你好運!

鏈接到代碼

暫無
暫無

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

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