![](/img/trans.png)
[英]Typescript infer object keys for function based on properties in the same object
[英]infer argument types of a function based on object keys
使用下面的代碼,我試圖根據args
的值推斷fn
的參數類型。
我需要將good
推斷為 boolean,將num
推斷為數字,將bad
推斷為錯誤。
現在他們都有類型string | number | boolean
string | number | boolean
string | number | boolean
,沒有報錯。
type WithArgs<
Args extends {
[key: string]: { value: [string, string | number | boolean] };
} = {
[key: string]: { value: [string, string | number | boolean] };
},
Arg extends keyof Args = keyof Args
> = {
args: Args;
fn: (params: { [key in Arg]: Args[Arg]["value"][1] }) => void;
};
const configs: WithArgs[] = [{
args: { good: { value: ["bool", true] } },
fn: ({ good, bad }) => {}
}, {
args: { num: { value: ["number", 5] } },
fn: ({ num }) => {}
}];
Typescript 只能推斷函數的類型。 由於您正在嘗試鍵入非函數,因此您的泛型類型必須接受一個參數。
如果我為該類型提供第一個參數,那么good
只能為 true,我們會收到一個 bad 錯誤,提示“TS2339:屬性‘bad’在類型‘{good: true;}’上不存在。”
const configs: WithArgs<{ good: { value: ['bool', true] } }>[] = [{
args: { good: { value: ["bool", true] } },
fn: ({ good, bad }) => {}
}];
當然我不確定你為什么要這樣做。 我很想知道。
編輯( 游樂場鏈接):
我接受了自己的建議。 知道 Typescript可以從函數推斷類型,那么我們需要做的就是創建一個 function。
首先,我添加了Args
的定義,並更新了WithArgs
類型:
type Args<T> = {
[key: string]: { value: [string, T] };
};
type WithArgs<
A extends Args<unknown> = {
[key: string]: { value: [string, string | number | boolean] };
},
Arg extends keyof A = keyof A
> = {
args: A;
fn: (params: { [key in Arg]: A[Arg]["value"][1] }) => void;
};
然后,我定義了一個 function 來推斷單個配置的類型:
const withArgs = <C, A extends Args<C>, F extends keyof A>(config: WithArgs<A, F>) => config;
現在我們得到了一個bad
錯誤:
const invalid = withArgs({
args: { good: { value: ["bool", true] } },
fn: ({ good, bad }) => {} // Property 'bad' does not exist on type '{ good: boolean; }'
});
當然,您希望能夠定義這些配置的數組。 所以我們可以定義一個 function 來正確地鍵入一個數組:
type GetWithArgs<T> = T extends WithArgs<infer A, infer F> ? WithArgs<A, F> : never;
const withArgsArr = <T extends WithArgs<Args<unknown>, string | number>[]>(...configs: T) => configs.map(withArgs) as { [i in keyof T]: GetWithArgs<T[i]> };
現在,我還沒有弄清楚這一點,但是當您以這種方式聲明整個配置時,似乎不會拋出錯誤。 類型錯誤僅在您隨后引用特定配置時發生。 我希望有人能幫助澄清這種行為(編輯: 我現在在這里問了這個問題)。
const shouldAlsoBeInvalid = withArgsArr(
{
args: { good: { value: ["bool", true] } },
fn: ({ good, bad }) => {}
}, {
args: { num: { value: ["number", 5] } },
fn: ({ num }) => {}
}
); // no errors yet :(
const requiresBool = shouldAlsoBeInvalid[0].fn({ good: 'string' }); // TS2322: Type 'string' is not assignable to type 'boolean'.
const badDoesNotExist = shouldAlsoBeInvalid[0].fn({ bad: 'string' }); // TS2345: Argument of type '{ bad: string; }' is not assignable to parameter of type '{ good: boolean; }'.
const requiresNumberParameter = shouldAlsoBeInvalid[1].fn({ num: '1' }); // TS2322: Type 'string' is not assignable to type 'number'.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.