31997-extreme-parameter-intersection

Back

type Arr = readonly unknown[];

type Intr<A, B> = [A, B] extends [object, object] ? {[K in keyof (A & B)]: (A & B)[K]} : A & B;

type IntersectParameters<X extends Arr, Y extends Arr, R extends Arr = []> = X extends readonly []
  ? [...R, ...Y]
  : Y extends readonly []
    ? [...R, ...X]
    : [X, Y] extends [readonly [(infer A)?, ...infer XT], readonly [(infer B)?, ...infer YT]]
      ? '0' extends (keyof X) | (keyof Y) 
        ? IntersectParameters<XT, YT, [[], []] extends [X, Y] ? [...R, Intr<A, B>?] : [...R, Intr<A, B>]>
        : [...R, ...Intr<A, B>[]]
      : never;

Solution by alexandroppolus #33210

type IntersectParameters<l extends readonly unknown[], r extends readonly unknown[]> =
  [VariadicType<l>, VariadicType<r>] extends [never, never]
    ? IntersectStaticParameters<l, r>
  : [...IntersectStaticParameters<l, r>, ...CombineTypes<[VariadicType<l>, VariadicType<r>]>[]]

type IntersectStaticParameters<
  l extends readonly unknown[],
  r extends readonly unknown[],
  Static extends any[] = [],
  I extends string = `${Static['length']}`,
> =
  I extends keyof l | keyof r
    ? [IsFinalElementOptional<I, l, Static>, IsFinalElementOptional<I, r, Static>] extends [true, true]
      ? [CombineParameterTypes<l, r, I>?, ...IntersectStaticParameters<l, r, [...Static, any]>]
    : [CombineParameterTypes<l, r, I>, ...IntersectStaticParameters<l, r, [...Static, any]>]
  : []

type IsFinalElementOptional<I, T extends readonly unknown[], Lead extends any[], TrueValue = true> =
  I extends keyof T
    ? T extends [...Lead, any, ...any[]]
      ? false
    : TrueValue
  : true

type CombineParameterTypes<L extends readonly unknown[], R extends readonly unknown[], K extends keyof L | keyof R> =
  K extends keyof L & keyof R
    ? CombineTypes<[L[K], R[K]]>
  : K extends keyof L
    ? CombineTypes<[L[K], VariadicType<R>]>
  : K extends keyof R
    ? CombineTypes<[R[K], VariadicType<L>]>
  : CombineTypes<[VariadicType<L>, VariadicType<R>]>

type CombineTypes<ToMerge extends unknown[], Merged = never> =
  ToMerge extends [infer First, ...infer Rest extends unknown[]]
    ? [Merged] extends [never]
      ? CombineTypes<Rest, First>
    : (Merged & First) extends infer Next
      ? [Next] extends [never]
        ? CombineTypes<Rest, Merged>
      : Next extends Record<PropertyKey, unknown>
        ? CombineTypes<Rest, {[K in keyof Next]: Next[K]}>
      : CombineTypes<Rest, Next>
    : never     // infer Next
  : Merged

type VariadicType<
  T extends readonly unknown[],
  Static extends any[] = [],
  I extends number = Static['length']
> =
  `${I}` extends keyof T
    ? VariadicType<T, [...Static, any?]>
  : T extends [...Static, ...infer Rest extends any[]]
    ? Rest[number]
  : never      // infer Rest

Playground

Copied from alexandroppolus solution https://github.com/type-challenges/type-challenges/issues/33210

type Intr<A, B> = [A, B] extends [object, object] ? {[K in keyof (A & B)]: (A & B)[K]} : A & B;

type IntersectParameters<X extends unknown[], Y extends unknown[], R extends unknown[] = []> =
  X extends []
    ? [...R, ...Y]
  : Y extends []
    ? [...R, ...X]
  : [X, Y] extends [[(infer FirstX)?, ...infer RestX extends unknown[]], [(infer FirstY)?, ...infer RestY extends unknown[]]]
    ? '0' extends (keyof X) | (keyof Y)
      ? [[], []] extends [X, Y]
        ? IntersectParameters<RestX, RestY, [...R, Intr<FirstX, FirstY>?]>
      : IntersectParameters<RestX, RestY, [...R, Intr<FirstX, FirstY>]>
    : [...R, ...Intr<FirstX, FirstY>[]]
  : never // infer FirstX, infer RestX, infer FirstY, infer RestY

// Test cases for each parts
type _S = {
  Emp: [];
  Tpl: [1];
  Arr: 2[];
  Opt: [3?];
  ArrInTpl: [...2[]];
  OptArr: [3?, ...2[]];
  TplOptArr: [1, 3?, ...2[]];
  TplArr: [1, ...2[]];
}
type _Test1 = Expect<Equal<{
  Emp: "✅";
  Tpl: "❌";
  Arr: "❌";
  Opt: "❌";
  ArrInTpl: "❌";
  OptArr: "❌";
  TplOptArr: "❌";
  TplArr: "❌";
}, {[I in keyof _S]: _S[I] extends [] ? '✅' : '❌'}>>
type _Test2 = Expect<Equal<{
    Emp: "❌";
    Tpl: "✅";
    Arr: "❌";
    Opt: "✅";
    ArrInTpl: "❌";
    OptArr: "✅";
    TplOptArr: "✅";
    TplArr: "✅";
}, {[I in keyof _S]: '0' extends keyof _S[I] ? '✅' : '❌'}>>
type _Test3 = Expect<Equal<{
    Emp: "❌";
    Tpl: "✅";
    Arr: "❌";
    Opt: "✅";
    ArrInTpl: "❌";
    OptArr: "✅";
    TplOptArr: "✅";
    TplArr: "✅";
}, {[I in keyof _S]: '0' extends keyof _S[I] ? '✅' : '❌'}>>
type _Test4 = Expect<Equal<{
    Emp: "❌";
    Tpl: "✅";
    Arr: "❌";
    Opt: "✅";
    ArrInTpl: "❌";
    OptArr: "✅";
    TplOptArr: "✅";
    TplArr: "✅";
}, {[I in keyof _S]: '0' extends keyof _S[I] ? '✅' : '❌'}>>
type _Test5 = Expect<Equal<never, Intr<1, 2>>>
type _Test5a = Expect<Equal<{a: 1, b: 2}, Intr<{a: 1}, {b: 2}>>>
type _Test5b = Expect<Equal<'a', Intr<string, 'a'>>>

Playground

Solution by teamchong #33163