typescript - 在迴圈中評估模板化的配置
我有一個系統配置(由我提供),它描述了用戶配置(由用戶提供)的能力。
然後我想傳遞使用者設定的每一部分,並根據系統設置進行評估。
為了說明我的意思,這裡有一些範例程式碼。它應該輸出兩行:
- 123
- 「隨便」
const systemConfig = {
a: (arg: number) => arg,
b: (arg: string) => arg,
}
type InferConfig<T extends {}> = { [K in keyof T]: T[K] extends (arg: infer U) => any ? U : never }
const userConfig: InferConfig<typeof systemConfig> = {
a: 123,
b: 'whateva',
};
// (everything above working as expected)
for (const key in userConfig) {
if (key in systemConfig) {
console.log(systemConfig[key](userConfig[key])); // correct output but highlights errors
console.log(systemConfig[key as keyof typeof systemConfig](userConfig[key as keyof typeof userConfig])); // luckily doesn't work because I want to avoid "as" if possible
}
}
操場
另一個要求是循環(程式碼中不起作用的部分)不得包含形如 “if (key === 'a') ...” 的邏輯(即不依賴 a)
答案#1
你的程式碼沒有包含對象類型 systemConfig 的索引簽名。這意味著任何使用 string 來索引 systemConfig 的嘗試都將被阻止。例如,我們可以這樣定義帶有索引簽名的對象:
const systemConfig: {[key: string]: (arg: any) => string | number} = {
a: (arg: number) => arg,
b: (arg: string) => arg,
}
在上述程式碼中,[key: string] 意味著可以使用 string 鍵來為 systemConfig 的屬性賦值。而 (arg: any) => string | number 意味著該值應該是一個函數,該函數接收一個 any 類型的參數並返回 string 或 number(你可以修改這個函數)
完成後,你可以移除這行多餘的程式碼並檢查它(遊樂場):
console.log(systemConfig[key as keyof typeof systemConfig](userConfig[key as keyof typeof userConfig]));
供您參考:TypeScript 的索引簽名實際上意味著什麼?
答案#2
通常我們先定義配置類型,然後再擴展轉換器。
但如果你真的想要它,請看下面的程式碼。
遊樂場
type ConfigTransformer = {
[K in string]: (arg: any) => any
}
type ConfigInput<T extends ConfigTransformer> = {
[K in keyof T]: T[K] extends (arg: infer U) => any ? U : never
}
type ConfigOutput<T extends ConfigTransformer> = {
[K in keyof T]: T[K] extends (arg: any) => infer U ? U : never
}
const systemConfig = {
a: (arg: number) => arg,
b: (arg: string) => arg,
}
type SystemInput = ConfigInput<typeof systemConfig>
type SystemOutput = ConfigOutput<typeof systemConfig>
const userConfig: SystemInput = {
a: 123,
b: 'whateva',
};
function transform<T extends ConfigTransformer>(transformer: T, input: ConfigInput<T>){
// you must do this `as` because typescript not infer the correct key type
const keys = Object.keys(transformer) as (keyof T)[];
for(const key of keys){
console.log(transformer[key](input[key]))
}
}
transform(systemConfig, userConfig);
