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
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'>>>
Solution by teamchong #33163