Skip to content

Instantly share code, notes, and snippets.

@mjy9088
Last active April 9, 2025 08:46
Show Gist options
  • Save mjy9088/c4320a9cb37e2b850c9f629be45dc854 to your computer and use it in GitHub Desktop.
Save mjy9088/c4320a9cb37e2b850c9f629be45dc854 to your computer and use it in GitHub Desktop.
TypeScript XOR with multiple operands
export type XOR<T extends any[]> = XORInternal1<
T,
XORInternal2<T, never>,
never
>;
type XORInternal2<T extends any[], R> = T["length"] extends 0
? R
: XORInternal2<RemoveFirst<T>, keyof T[0] | R>;
type RemoveFirst<T extends any[]> = T extends [any, ...infer I] ? I : never;
type XORInternal1<
T extends any[],
K extends keyof any,
R
> = T["length"] extends 0
? R
: XORInternal1<
RemoveFirst<T>,
K,
R | (Partial<Record<Exclude<K, keyof T[0]>, undefined>> & T[0])
>;
import type { XOR } from './XOR.ts';
type ExpandRecursively<T> = T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T;
type Test = ExpandRecursively<
XOR<[{ a: string }, { b: number }, { c: string; d: number }]>
>;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment