- Published on
Takeway: Create XOR Type in Typescript 🚧
- Authors
- Name
- Omar Khairy
- @omark4y
The Problem
Last week i encountered a type porblem where i had existing type, let say x it as the following type
type example = {
x: string
y: string
}
I wanted to add z to the type but i wanted to make sure that only one of the y or z is present at a time. But not both at the same time.
The Solution
Simple that is a XOR problem. I can create a XOR type in typescript like this
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }
type XOR<T, U> = T | U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U
let's break it down
Without<T, U>
: This is a utility type that will return the properties of T that are not present in U.T | U extends object
: This is a conditional type that checks if T or U is an object(Without<T, U> & U) | (Without<U, T> & T)
: This is the actual XOR type. It checks if T is present and U is not present and vice versa.T | U
: This is the base case. If T or U is not an object then it will just return T or U.
Example
type example = {
x: string
} & XOR<{ y: string }, { z: string }>
const a: example = {
x: 'hello',
y: 'world',
} // it works
const b: example = {
x: 'hello',
z: 'world',
} // it works
const c: example = {
x: 'hello',
y: 'world',
z: 'world',
} // it does not work
But there is a problem
when you hover over the type in your IDE you will see a lint error like this

The type is very hard to read and understand. I was playing around to make it look pretty i found type package called ts-xor which does the same thing but it looks pretty.
Here is result of using ts-xor
import type { XOR } from 'ts-xor'
type example = {
x: string
} & XOR<{ y: string }, { z: string }>
here how it looks in the IDE:
