我想在 TypeScript 中設計一個函式,它訪問復雜結構的欄位名稱并回傳該欄位的型別。例如,有一個Settings
包含多個欄位的型別:
export interface Settings {
apiConfig?: ApiConfig;
presentation?: PresentationSettings;
}
我想要一個getSettings
可以用作的功能:
let cfg: ApiConfig = getSettings('apiConfig');
let ui: PresentationSettings = getSettings('presentation');
我的第一種方法是使用 keyof:
function getSettings(name: keyof Settings): Settings[keyof Settings] {
if (name == 'apiConfig') {
return store.get(name) as ApiConfig;
}
if (name == 'presentation') {
return store.get(name) as PresentationSettings;
}
}
但這意味著回傳型別基本上是 ApiConfig | 的并集 演示設定。所以我必須投:
const ui = <PresentationSettings>getSettings('presentation');
不理想。
下一個方法是泛型:
export function getSettings<T extends Settings[keyof Settings]>(
name: keyof Settings
它可以用作:
const ui = getSettings<PresentationSettings>('presentation');
但是在實作功能時:
export function getSettings<T extends Settings[keyof Settings]>(
name: keyof Settings
{
if (name == 'apiConfig') {
return store.get(name) as ApiConfig;
}
}
我收到錯誤:型別“ApiConfig”不可分配給型別“T”。“ApiConfig”可分配給“T”型別的約束,但“T”可以用約束“ApiConfig |”的不同子型別來實體化。演示設定'.ts(2322)
所以它必須被強制轉換為any
. 也不理想。
還有其他方法嗎?
特別是我想稱之為沒有任何演員: const ui = getSettings('presentation'); 并有一個PresentationSettings
. 那可能嗎?
uj5u.com熱心網友回復:
該功能肯定需要是通用的。但T
不應該是回傳型別,而應該只是鍵。回傳型別可用于T
索引Settings
。
function getSettings<T extends keyof Settings>(name: T): Settings[T] {
return {
apiConfig: store.get(name) as ApiConfig,
presentation: store.get(name) as PresentationSettings
}[name]
}
如果您希望在實作中沒有錯誤,則必須使用某種映射結構,如上圖所示。
這個實作的問題是store.get
物件中的每個呼叫都將被急切地執行,如果它是一個昂貴的呼叫,這是不理想的。為避免這種情況,您可以只使用普通switch
陳述句。但是你需要一些斷言來消除錯誤。
function getSettings<T extends keyof Settings>(name: T): Settings[T] {
switch (name) {
case "apiConfig": { return store.get(name) as Settings[T] }
case "presentation": { return store.get(name) as Settings[T] }
default: { return undefined as Settings[T] }
}
}
如果您想要完全型別安全并且不急切執行所有路徑,您可以使用包含函式的映射。這里唯一的缺點是額外的函式呼叫,它可能看起來太冗長了。
function getSettings<T extends keyof Settings>(name: T): Settings[T] {
const mapping: {
[K in keyof Settings]: () => Settings[K]
} = {
apiConfig: () => store.get(name) as ApiConfig,
presentation: () => store.get(name) as PresentationSettings
}
return mapping[name]()
}
操場
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/527578.html
標籤:打字稿
上一篇:如何從物件聯合中獲取物件值型別