I attempted to create a type definition for recurrent intersection, in order to achieve this specific behavior:
type merged = Merged<[{a: string}, {b: string}, ...]>
to end up with
{a: string} & {b: string} & ...
I came up with some type utilities like Head
and Tail
to work with a variable number of input types and successfully implemented recurrent union, but struggled when it came to achieving the same for intersection :(
type Head<T extends any[]> = T[0]
type Tail<T extends any[]> =
((...args: T) => any) extends ((_arg0: any, ...rest: infer R) => any) ? R : never
type United<T extends any[]> = {
0: Head<T>
1: United<Tail<T>>
}[ T extends ([] | [any])
? 0
: 0 | 1
]
type Merged<T extends any[]> = {
0: Head<T>
1: Merged<Tail<T>>
}[T extends ([] | [any])
? 0
: 0 & 1
]
type a = {a: string}
type b = {b: string}
type c = {c: string}
type head = Head<[a, b, c, d]> // {a: string} OK
type tail = Tail<[a, b, c, d]> // [b, c] OK
type united = United<[a, b, c, d]> // a | b | c OK
type merged = Merged<[a, b, c, d]> // unknown Not good
It seems like I may be missing some fundamental TypeScript concepts, as I can't figure out why it succeeded with union but not with intersection?
Any suggestions on how I could potentially resolve this issue?