Home > Blockchain >  Typescript generic depends on order of parameters, while it should not
Typescript generic depends on order of parameters, while it should not

Time:03-22

I have generic mergeArrays which does not depend on order of parameters. But when used inside another generic it seems result depend. But it is not understandable.

type Fn = (...args: any[]) => any;

type arr1LessThanOrEqual<
  T1 extends ReadonlyArray<any>,
  T2 extends ReadonlyArray<any>
  > = T1["length"] extends T2["length"]
  ? true
  : T2["length"] extends 0
  ? false
  : T2 extends [infer First, ...infer Rest]
  ? Rest extends ReadonlyArray<any>
  ? arr1LessThanOrEqual<T1, Rest>
  : never
  : never;

type mergeArrWithLeft<
  T1 extends ReadonlyArray<any>,
  T2 extends ReadonlyArray<any>
  > = readonly [
    ...{
      readonly [Index in keyof T1]: Index extends keyof T2
      ? (T1[Index] & T2[Index])
      : T1[Index];
    }
  ];

type mergeArrays<
  T1 extends ReadonlyArray<any>,
  T2 extends ReadonlyArray<any>
  > = arr1LessThanOrEqual<T1, T2> extends true
  ? mergeArrWithLeft<T2, T1>
  : mergeArrWithLeft<T1, T2>;

and here i use this generic:

type LargestArgumentsList<T extends ReadonlyArray<any>> = T extends readonly [
  (...args: infer Args) => any,
  ...infer Rest
] ?
  mergeArrays<LargestArgumentsList<Rest>, Args> // here if I swap it does not work, but generic mergeArrays does not depend on order of params, so  it is a  mistery
  : readonly [];

and it works. but if i swap it to:

type LargestArgumentsList<T extends ReadonlyArray<any>> = T extends readonly [
  (...args: infer Args) => any,
  ...infer Rest
] ?
  mergeArrays<Args, LargestArgumentsList<Rest>>
  : readonly [];

the behaviour of LargestArgumentsList is different, here is playground

I tried to create a generic which finds the longest list of arguments in array of function. And i expect mergeArrays generic to not depend on order of parameters. I tested and it does not depend on order of parameters. But inside another generic(LargestArgumentsList) it works differently.

CodePudding user response:

The definition of arr1LessThanOrEqual is missing a readonly in the T2 extends [infer First, ...infer Rest] constraint. Since Args is not readonly, arr1LessThanOrEqual works when Args is the second parameter, but if you swap it with the readonly LargestArgumentsList<Rest>, it will fail.

If you replace the constraint with

T2 extends readonly [infer First, ...infer Rest]

LargestArgumentsList will work even when the parameters are swapped.

TypeScript playground

  • Related