Last active
April 9, 2025 08:46
-
-
Save mjy9088/c4320a9cb37e2b850c9f629be45dc854 to your computer and use it in GitHub Desktop.
TypeScript XOR with multiple operands
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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]) | |
>; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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