如何鍵入有時會退出行程的異步函式?
我希望能夠像這樣使用它:
function useResult(result:Result): void {
// ...
}
const result: Result | undefined = await getResult();
if (result === undefined) reportError({ fatal: true });
useResult(result) // I want the type of result to be `Result` here, not `Result | undefined`
const result: Result | undefined = await getResult();
if (result === undefined) reportError({ fatal: false });
useResult(result) // I want the type of result to be `Result | undefined` here
這是有問題的功能:
import { exit } from "node:process";
interface ReportableError {
fatal?: true | false | undefined;
// ...
}
export async function reportError<E extends ReportableError>(
e: E,
) { // <-- How do I type the return of this function?
// Log the error, do some async stuff...
if (e.fatal) {
// Stop running
exit();
}
// Continue running
}
uj5u.com熱心網友回復:
我認為唯一可行的方法是,如果您為“致命”和“非致命”型別的輸入創建一個具有單獨呼叫簽名reportError()的多載函式。
本質上你想reportError({fatal: true})回傳型別,never因為函式永遠不會回傳。當您呼叫呼叫簽名的回傳型別為 just 的函式時never,編譯器可以使用控制流分析來根據代碼的可達性來縮小變數的型別。這是在microsoft/TypeScript#32695中實作的,并且只有在回傳型別被顯式注釋為 just 時才會觸發never。
既然你想要
if (result === undefined) reportError({ fatal: true });
to 縮小resultfrom Result | undefinedto Result,表示reportError()必須回傳 a never。所以一個呼叫簽名reportError應該看起來像
function reportError(e: { fatal: true }): never;
請注意,我們無法撰寫async function reportError(e: {fatal: true}): Promise<never>,因為它不會以我們想要的方式影響可達性......這在microsoft/TypeScript#34955Promise<never>被標記為錯誤。
另一方面,當您呼叫reportError()where fatalis not時true,您希望 this 只是一個異步函式,它回傳void... Promise<void>像這樣:
async function reportError(e: { fatal?: false | undefined }): Promise<void>;
我們必須將致命和非致命案例分離到它們自己的呼叫簽名中,以便可達性分析按我們的意愿作業。回傳條件型別like的單個泛型呼叫簽名在概念上是相同的,但編譯器不會將其視為斷言。<E>(e: ReportableError) => E extends {fatal: true} ? never : Promise<void>
好的,所以我們有兩個呼叫簽名,我們需要一個實作。完整的功能看起來像
function reportError(e: { fatal: true }): never;
async function reportError(e: { fatal?: false | undefined }): Promise<void>;
async function reportError(e: ReportableError) {
if (e.fatal) {
throw new Error("EXITING PROCESS OR SOMETHING");
}
}
讓我們看看它是否按我們想要的方式作業:
const result: Result | undefined = await getResult();
if (result === undefined) reportError({ fatal: true });
useResult(result) // okay
太好了,result變窄了。如果我們改變致死率:
const result: Result | undefined = await getResult();
if (result === undefined) reportError({ fatal: false });
useResult(result) // error! undefined is not assignable to Result
現在result沒有縮小,編譯器不喜歡useResult(result)因為useResult()不接受undefined.
Playground 代碼鏈接
uj5u.com熱心網友回復:
export async function reportError<E extends ReportableError>(
e: E,
): E["fatal"] extends true ? never : Promise<Result | undefined> {
// ...
}
查看條件型別
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/486002.html
