[英]Narrow union type based on literal property value
我認為我的用例很常見; 我正在嘗試鍵入一個 HTTP 響應 object,這樣只有在狀態代碼恰好為 200 時才可靠地定義正文。我想將 object 作為ResponseType
類型返回,這樣調用我的 function 的人可以返回它例如:
function doSomething<T extends {property: "value"}>(r: ResponseType<T>): void {
if (r.status === 200) {
// r.body has the type 'T & {property: "value"}' here
console.log(r.body.property);
} else {
// r.body has the type 'undefined' here
console.log("no body");
}
}
所以,為了做到這一點,我嘗試過:
type ResponseType<T> = {
body: T;
status: 200;
} | {
body: undefined;
status: Exclude<number, 200>;
};
但這不起作用,因為number
不是聯合類型,並且由於number
不可分配給200
,但200
可分配給number
,這最終等同於
type ResponseType<T> = {
body: T;
status: 200;
} | {
body: undefined;
status: number;
};
並且因為檢查數字的number
不會將其縮小到您要檢查的常量(即使您要執行例如if (resp.status === 200 as const)
或if (resp.status === 200 as 200)
), 這又等同於
// requires --noUnusedParameters to be 'false'
type ResponseType<T> = {
body: undefined;
status: number;
}
因為200
和number
是不同的類型——即使一個可以分配給另一個——我強烈認為必須有一種方法來告訴 TypeScript 可以安全地根據另一個屬性是這些類型中的哪些類型來推斷對象屬性的類型,無需調用者編寫運行時類型保護檢查。 但是我該怎么做呢?
我想不出其他方法來實現你想要的。 這是我的解決方案。
type T200Response<T> = {
body: T;
status: 200;
}
type TNon200Response= {
body: undefined;
status: number;
}
function is200Response<T>(response: TResponse<T>): response is T200Response<T> {
return response.status === 200;
}
type TResponse<T> = T200Response<T> | TNon200Response;
function doSomething<T extends {property: "value"}>(r: TResponse<T>): void {
// is200Response to hints TS which type is it.
// If this function return true then TS will assume r is T200Response<T> within the if clause
if (is200Response<T>(r)) {
// r.body has the type 'T & {property: "value"}' here
r.body; // Mouseover body you will see T
console.log(r.body.property);
} else {
r.body; // Mouseover body you will see undefined
// r.body has the type 'undefined' here
console.log("no body");
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.