Does Typescript support mutually exclusive types?

Issue

I have a method that takes a parameter. I would like Typescript to verify that the object being passed in (at typescript compile-time, I understand run-time is a different animal) only satisfies one of the allowed interfaces.

Example:

interface Person {ethnicity: string;}
interface Pet {breed: string;}
function getOrigin(value: Person ^ Pet){...}

getOrigin({}); //Error
getOrigin({ethnicity: 'abc'}); //OK
getOrigin({breed: 'def'}); //OK
getOrigin({ethnicity: 'abc', breed: 'def'});//Error

I realize that Person ^ Pet is not valid Typescript, but it’s the first thing I thought to try and seemed reasonable.

Solution

As proposed in this issue, you could use conditional types to write a XOR type:

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;

And now your example works:

interface Person {ethnicity: string;}
interface Pet {breed: string;}
function getOrigin(value: XOR<Person, Pet>) { /* ... */}

getOrigin({}); //Error
getOrigin({ethnicity: 'abc'}); //OK
getOrigin({breed: 'def'}); //OK
getOrigin({ethnicity: 'abc', breed: 'def'});//Error

Answered By – Guilherme Agostinelli

Answer Checked By – Timothy Miller (AngularFixing Admin)

Leave a Reply

Your email address will not be published.