Skip to content

Instantly share code, notes, and snippets.

@webstrand
Last active April 20, 2023 14:04
Show Gist options
  • Save webstrand/0af759e21f1e6bc418c605fdddfba4b1 to your computer and use it in GitHub Desktop.
Save webstrand/0af759e21f1e6bc418c605fdddfba4b1 to your computer and use it in GitHub Desktop.
UnionToIntersection implemented without using intermediate function
type UnionToIntersection<
T,
U = T extends unknown ? { _: { [_ in T & PropertyKey]: never } } : {},
V = keyof U[keyof U],
// We need to remove the primitive we branded T with when we made it a
// property key. However, if the union T contains a branded type already,
// we must avoid stripping those brands off.
X = true extends (T extends PropertyKey ? true : never) ? never : PropertyKey
> = T extends never ? never : V extends X & infer W ? W : V;
// Beware: After 3.6, intersections of primtive types, such as `"foo" & "bar"`
// are immediately simplified to `never`. As such, this type will not work on a
// union containing multiple incompatible primitive types.
type u = UnionToIntersection<Date | Function>; // Date & Function
type v = UnionToIntersection<Date | Function & symbol>; // Date & Function & symbol
// There's an issue with untyped enum brands:
// But it doesn't matter since untyped enums are covariant with `number` anyway.
const enum Brand { };
type w = UnionToIntersection<Date | Function & Brand>; // Date & number & Function & Brand
// compare
type NormalUnionToIntersection<
T,
U = T extends unknown ? (k: T) => unknown : never
> = U extends ((k: infer V) => unknown) ? V : never;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment