I was surprised to find that TypeScript won\'t complain at me doing something like this:
type sth = { value: number, data: string } | { value: number, note:
Another option is to use optional never
properties to explicitly disallow a mix of fields from the two types in the union:
type sth =
{ value: number, data: string; note?: never; } |
{ value: number, note: string; data?: never; };
const a: sth = { value: 7, data: 'test' };
const b: sth = { value: 7, note: 'hello' };
const c: sth = { value: 7, data: 'test', note: 'hello' };
// ~ Type '{ value: number; data: string; note: string; }'
// is not assignable to type 'sth'.
The ts-essentials
library has an XOR generic that can be used to help you construct exclusive unions like this:
import { XOR } from 'ts-essentials';
type sth = XOR<
{ value: number, data: string; },
{ value: number, note: string; }
>;
const a: sth = { value: 7, data: 'test' };
const b: sth = { value: 7, note: 'hello' };
const c: sth = { value: 7, data: 'test', note: 'hello' };
// ~ Type '{ value: number; data: string; note: string; }'
// is not assignable to type ...
Here's a playground link for that last example.