maaartinus
maaartinus

Reputation: 46432

Working with typescript non-discriminated unions

I wonder if there's a sane way how to get the following to work.

interface IPerson {
  firstName: string
  lastName: string
}

interface IPet {
  name: string
}

type IPersonOrPet = IPerson | IPet

function fullname(p: IPersonOrPet) {
  if (p.name) {                                     // **1**
    return p.name                                   // **2**
  } else {
    return p.firstName + ' ' + p.lastName           // **3**
  }
}

I see that with discriminated unions, sich things are simple, but I can't see why nothing works for non-discriminated unions:

Upvotes: 1

Views: 515

Answers (2)

SpencerPark
SpencerPark

Reputation: 3506

You can use the in operator as a type guard which typescript will use to properly narrow the types within the condition bodies.

function fullname(p: IPersonOrPet) {
  if ('name' in p) {                                // **1**
    return p.name                                   // **2**
  } else {
    return p.firstName + ' ' + p.lastName           // **3**
  }
}

Upvotes: 4

user6269864
user6269864

Reputation:

The proper way to address this in TypeScript is to use a type guard, a function whose return type confirms or rejects your hypothesis that p belongs to Person or to Pet.

Check out the return type of the isPerson() function:

interface Person {
  firstName: string
  lastName: string
}

interface Pet {
  name: string
}

type PersonOrPet = Person | Pet

function fullname(p: PersonOrPet) {
  if (isPerson(p)) {
    return p.firstName + ' ' + p.lastName;
  } else {
    return p.name;
  }
}

function isPerson(p: PersonOrPet): p is Person {
  return 'firstName' in p && 'lastName' in p;
}

Upvotes: 2

Related Questions