Home > OS >  How to tell Typescript that casting from a less strict interface to a more strict one is ok?
How to tell Typescript that casting from a less strict interface to a more strict one is ok?

Time:06-22

I'm trying to get the code I've pasted below to execute but the Typescript compiler seems to be unconvinced that I've properly ensured one interface can be cast to another based on the check I've put. What do I need to do to make it happy with this code?


interface Person {
  name: string,
  address?: string
}

interface PersonWithAddress extends Person {
  address: string
}

function tryLoggingAddresses(people: Array<Person>) {
  people.forEach(person => {
    if (person.address) {
      logAddress(person)
    }
  })
}

function logAddress(personWithAddress: PersonWithAddress) {
  console.log(personWithAddress.address)
}

Typescript error:

error TS2345: Argument of type 'Person' is not assignable to parameter of type 'PersonWithAddress'.
      Types of property 'address' are incompatible.
        Type 'string | undefined' is not assignable to type 'string'.
          Type 'undefined' is not assignable to type 'string'.

    63       logAddress(person)

I know that I can force the cast by changing the line to logAddress(person as PersonWithAddress) but that's effectively disabling all type checking which isn't ideal. Is there anyway to do this without that?

CodePudding user response:

You can utilize a type guard in place of your existing conditional expression. This will help inform the compiler that the data structure meets the criteria that you intend during control flow analysis.

TypeScript Playground

function personHasAddress (person: Person): person is PersonWithAddress {
  return typeof person.address === 'string';
}

function logAddresses (people: Person[]) {
  for (const person of people) {
    if (personHasAddress(person)) logAddress(person);
  }
}
  • Related