我希望最新版本的 TS(參見例如#43183)可以使這種模式成為可能,而無需不安全的強制轉換。有任何想法嗎?(操場)
export type Mapping = {
number: number;
string: string;
};
function get<K extends keyof Mapping>(key: K): Mapping[K] {
switch (key) {
case "number":
// ERROR: Type 'number' is not assignable to type 'Mapping[K]'
return 42; // Adding "as Mapping[K]" works, but that's not type-safe
case "string":
// ERROR: Type 'string' is not assignable to type 'Mapping[K]'
return "hello";
default:
throw "Never reached, but otherwise TS throws: Function lacks...";
}
}
const usageWorksAsExpected = { n: get("number"), s: get("string") };
uj5u.com熱心網友回復:
不,在microsoft/TypeScript#43183中實作的 TypeScript 4.3 中添加的對泛型背景關系縮小的支持并沒有達到您的預期。此支持將from的型別縮小到or 或,但不會縮小型別引數本身的型別。即使確認為,型別引數也沒有改變,因此編譯器無法驗證可分配給。這令人沮喪。keyK"number""string"Kkey"number"K42Mapping[K]
有一些未解決的問題,例如microsoft/TypeScript#33014和microsoft/ TypeScript#27808,它們提出了編譯器可能縮小K自身的方式。但這些還沒有實施。
如果您想重寫get()以使其編譯時沒有錯誤并且不放棄型別安全,那么您可以這樣做:
function get<K extends keyof Mapping>(key: K): Mapping[K] {
return {
number: 42,
string: "hello"
}[key] // okay
}
您的回傳型別是通用索引訪問型別 Mapping[K]。編譯器可以驗證,如果你用 typeMapping的鍵索引一個 type 的值K,你將得到一個 type 的值Mapping[K],這就是上面重寫的代碼有效的原因。
這依賴于獲取 type 的值Mapping。有時您不能或不想這樣做,因為當您不想這樣做時,它會迫使您急切地預先計算每個可能輸入的結果。如果是這樣,您可以改為實作getter,以便Mapping延遲計算物件:
function get<K extends keyof Mapping>(key: K): Mapping[K] {
return {
get number() { return 42 },
get string() { return "hello" }
}[key]
}
Playground 代碼鏈接
uj5u.com熱心網友回復:
您的代碼對應于Suggestion for Dependent-Type-Like Functions: Conservative Narrowing of Generic Indexed Access Result Type #33014
該問題尚未解決,但其中一條評論建議以下解決方法:
export type Mapping = {
number: number;
string: string;
};
function get<K extends keyof Mapping>(key: K): Mapping[K]
function get(key: keyof Mapping) : Mapping[keyof Mapping] {
switch (key) {
case "number": {
const ret: Mapping[typeof key] = 42;
const ret1: Mapping[typeof key] = 'hello'; // Expected error
return ret;
}
case "string": {
const ret: Mapping[typeof key] = 'hello';
return ret;
}
default:
throw "Never reached, but otherwise TS throws: Function lacks...";
}
}
const usageWorksAsExpected = { n: get("number"), s: get("string") };
游樂場鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/468683.html
上一篇:型別“鍵”不能用于索引TypeScript中的型別“物件”
下一篇:從物件型別構造聯合型別
