簡體   English   中英

動態函數的返回類型

[英]Return typings for dynamic functions

我有一個 function,它唯一的邏輯是執行傳入的 function。

const funcRunner = async (func: Function) => {
   return await func()
}

我知道無論傳入的 function 的響應如何,都將是同一個 function 的響應。

然而,這個 function 返回簽名被推斷為Promise<any> 有什么辦法可以保留原來function的響應類型?

const bool = async isExample(): Promise<boolean> => true;

// result should be boolean, not any
const result = await funcRunner(isExample);

您可以將其設為通用,這樣 TypeScript 就可以從調用站點推斷出來,並使用實用程序類型ReturnType來獲取其返回類型:

const funcRunner = async <FuncType extends () => any>(
    func: FuncType
): Promise<ReturnType<FuncType>> => {
   return await func();
};

使用示例:

async function example1() {
    return 1;
}

async function example2() {
    return "a";
}

(async() => {
    const result1 = await funcRunner(example1);
    //    ^? const result1: number
    const result2 = await funcRunner(example2);
    //    ^? const result2: string
})();

游樂場鏈接

如果願意,您可以通過不將funcRunner設為async來使其更通用一些,然后它可以運行async或非異步函數,而無需向非async函數添加async

const funcRunner = <FuncType extends () => any>(
    func: FuncType
): ReturnType<FuncType> => {
    return func();
};

游樂場鏈接

如果您想確保在異步堆棧跟蹤中看到funcRunner ,您可能不想這樣做,但如果您不為此煩惱,那很好。


只是為了好玩:如果你想讓funcRunner調用需要參數的函數,你可以添加一個完全類型化的args參數:

async function funcRunner<FuncType extends (...args: any[]) => any>(
    func: FuncType,
    args: Parameters<FuncType>
): Promise<ReturnType<FuncType>> {
    return await func(...args);
}

如果你想讓第二個參數對於不帶任何參數的函數是可選的,我認為你需要重載它:

async function funcRunner<FuncType extends () => any>(
    func: FuncType,
): Promise<ReturnType<FuncType>>;
async function funcRunner<FuncType extends (...args: any[]) => any>(
    func: FuncType,
    args: Parameters<FuncType>
): Promise<ReturnType<FuncType>>;
async function funcRunner<FuncType extends (...args: any[]) => any>(
    func: FuncType,
    args?: Parameters<FuncType>
): Promise<ReturnType<FuncType>> {
    if (args) {
        return await func(...args);
    }
    return await func();
}

重載的用法示例:

async function example1() {
    return 1;
}

async function example2() {
    return "a";
}

function example3() {
    return Math.random() < 0.5;
}

function example4(num: number) {
    return num * 42;
}

(async() => {
    const result1 = await funcRunner(example1);
    //    ^?
    const result2 = await funcRunner(example2, []); // <=== Args is allowed even when optional...
    //    ^?
    const badResult1 = await funcRunner(example2, ["x"]); // <=== ...but it can't have anything in it
    //    ^?
    const result3 = await funcRunner(example3);
    //    ^?
    const result4 = await funcRunner(example4, [3]);
    //    ^?
    const badResult2 = await funcRunner(example4); // <=== Error as desired, need args!
    //    ^?
    const badResult3 = await funcRunner(example4, ["x"]); // <=== Error as desired, wrong type!
    //    ^?
})();

游樂場鏈接

當然,您也可以始終使那個async -neutral; 游樂場鏈接

可以定義一個泛型來運行 function:

type Runnable<T> = () => Promise<T>;

然后將其應用於您的funcRunner

async function funcRunner<T>(runnable: Runnable<T>): Promise<T> {
  return await runnable();
}

您可以選擇使用內聯輸入:

async function funcRunner<T>(runnable: () => Promise<T>): Promise<T> {
  return await runnable();
}

用法示例:

async function example1(): Promise<number> {
  return 1;
}


funcRunner(example1)
    .then((result: number) => console.log(result))

暫無
暫無

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

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