One-or-the-other properties

Posted on

We can define a type in which only one of two mutually exclusive properties should exist.

We first need to create a base interface that holds all properties that always exist. We then extend new interfaces from that base, one for each of the exclusive variants.

In each of these, we then set one of the properties to a regular type and the other to optional (?) and never.

Our final type is the union of the two variant interfaces.

interface Base {
  // all shared properties
}
 
interface VariantA extends Base {
  one: string
  two?: never
}
 
interface VariantB extends Base {
  one?: never
  two: string
}
 
type Thing = VariantA | VariantB
interface Base {
  // all shared properties
}
 
interface VariantA extends Base {
  one: string
  two?: never
}
 
interface VariantB extends Base {
  one?: never
  two: string
}
 
type Thing = VariantA | VariantB

We can then use that type for both variants. Setting either one of the mutually exclusive properties is fine, setting both isn’t.

// this is fine
const a: Thing = {
  one: "hello",
}
 
// this is also fine
const b: Thing = {
  two: "world",
}
 
// this is not allowed
const c: Thing = {
  one: "hello",
  two: "world",
}
// this is fine
const a: Thing = {
  one: "hello",
}
 
// this is also fine
const b: Thing = {
  two: "world",
}
 
// this is not allowed
const c: Thing = {
  one: "hello",
  two: "world",
}
Debug
none
Grid overlay