Today I Learned

Creating a type that requires alternative fields

In order to create a type that should require one of the alternative fields be required, use the union with alternative. For instance, the following type requires a person to have either socialSecurityNumber or dateOfBirth present:

type Person = {
  name: string
} & (
  | { socialSecurityNumber: string }
  | { dateOfBirth: string}
)

The first part contains a standard set of fields:

type Person = {
  name: string
} 

that is combined with two alternative types using the union (&) and alternative (|) signs:

& (
  | { socialSecurityNumber: string}
  | { dateOfBirth: string}
)

Then these examples are valid:

const simon: Person = {
  name: 'simon',
  socialSecurityNumber: 'ssn'
}

const peter: Person = {
  name: 'peter',
  dateOfBirth: '01.01.1901'
}

const pete: Person = {
  name: 'peter',
  dateOfBirth: '01.01.1901',
  socialSecurityNumber: 'ssn'
}

But an object containing just name will generate an error:

const invalidPerson: Person = {
  name: 'peter',
}

Type '{ name: string; }' is not assignable to type 'Person'.
  Type '{ name: string; }' is not assignable to type '{ name: string; } & { dateOfBirth: string; }'.
    Property 'dateOfBirth' is missing in type '{ name: string; }' but required in type '{ dateOfBirth: string; }'.