網站搜尋

在 TypeScript 的非同步函式中回傳一個 Promise


據我所知,這兩個函數在 JavaScript 中會有相同的行為:

const whatever1 = (): Promise<number> => {
    return new Promise((resolve) => {
        resolve(4);
    });
};

const whatever2 = async (): Promise<number> => {
    return new Promise((resolve) => {
        resolve(4);
    });
};

但 TypeScript 似乎不喜歡第二個,它說:

Type '{}' is not assignable to type 'number'.

這是 TypeScript 的錯誤,還是我對 async 函數有所誤解?

答案#1

這很複雜。

首先,在這段程式碼中

const p = new Promise((resolve) => {
    resolve(4);
});

p 的類型被推斷為 Promise<{}>。在 TypeScript 的 GitHub 上有開放的相關問題,因此可以說這是一個 bug,因為很明顯(對人類而言),p 應該是 Promise<number>。

然後,Promise<{}> 與 Promise<number> 是相容的,因為基本上 promise 唯一的屬性是 then 方法,而依據 TypeScript 函數型別相容性規則,then 在這兩種 promise 型別中是相容的。這就是為什麼 whatever1 不會報錯的原因。

但 async 的目的是假裝你在處理的是實際值,而不是 Promise,然後你在 whatever2 中得到錯誤,因為 {} 顯然與 number 不兼容。

所以 async 的行為是相同的,但目前需要一些變通方法才能讓 TypeScript 編譯它。你可以在創建 promise 時簡單地提供明確的泛型參數,如下所示:

const whatever2 = async (): Promise<number> => {
    return new Promise<number>((resolve) => {
        resolve(4);
    });
};

答案#2

當你使用 new Promise((resolve)... 時,推斷的類型是 Promise<{}>,因為你應該使用 new Promise<number>((resolve)。

有趣的是,這個問題只有在加入 async 關鍵字時才被突顯出來。我建議在 GitHub 上向 TS 團隊報告這個問題。

有許多方法可以解決這個問題。以下所有函數的行為都是相同的:

const whatever1 = () => {
    return new Promise<number>((resolve) => {
        resolve(4);
    });
};

const whatever2 = async () => {
    return new Promise<number>((resolve) => {
        resolve(4);
    });
};

const whatever3 = async () => {
    return await new Promise<number>((resolve) => {
        resolve(4);
    });
};

const whatever4 = async () => {
    return Promise.resolve(4);
};

const whatever5 = async () => {
    return await Promise.resolve(4);
};

const whatever6 = async () => Promise.resolve(4);

const whatever7 = async () => await Promise.resolve(4);

在你的 IDE 中,你將能看到所有這些函數的推斷類型是 () => Promise<number>。