簡體   English   中英

根據 object 鍵推斷 function 的參數類型

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM