/** * This utility is easily comparable to function overloading in TypeScript. * * ```ts * // helper for overloading with generics. Not robust enough for overloads that change the return type. * type CreateOverload = UnionToIntersection< * Union extends unknown ? (u: Union) => Returns : never * > * * type BarProps = { kind: 0; enabled: boolean } | { kind: 1; fn: () => void } * type Bar = CreateOverload * * const bar: Bar = (u) => { * if (u.kind === 0) { * u.enabled * } else { * u.fn() * } * } * // * // ((u: { * // kind: 0; * // enabled: boolean; * // }) => void) & ((u: { * // kind: 1; * // fn: () => void; * // }) => void) * ``` * * @example * `arg` is narrowed as ts checks the function sequentially from top to bottom, stopping at the first match. * ```ts * function foo(arg: number): number * function foo(arg: string): string * function foo(arg: string | number): string { * return arg * } * ``` * `foo` can be represented using an interface: * ```ts * interface Foo { * (arg: number): number * (arg: string): string * (arg: string | number): string * } * ``` * ```ts * declare function Some(): T * declare const foo: Foo * * //@ts-expect-error - `arg` in `foo` must be a string or number * foo(Some()) // 🚨✅ * foo(Some<40>()) // (arg: number) => number (+2 overloads) // ✅ * foo(Some()) // (arg: number) => number (+2 overloads) // ✅ * foo(Some()) // (arg: number) => number // ✅ * foo(Some()) // (arg: string) => string (+2 overloads) // ✅ * foo(Some()) // (arg: string | number) => string (+2 overloads) // ✅ * ``` * you could overload arrow functions like this as well, but you need a type parameter to do it: * ```ts * const foo = (arg: T) => arg // const foo: Foo ✅ * ``` */ export type UnionToIntersection = ( Union extends unknown ? (u: Union) => void : never ) extends (u: infer Intersection) => void ? Intersection : never