Home > Software design >  How do I type-safely access the properties of an array element after narrowing on another property?
How do I type-safely access the properties of an array element after narrowing on another property?

Time:09-23

Basically, I have an array of two types of animal: Cat and Dog. I would like to be able to access the properties of the cat when I know it's a Cat, and access the properties of dog when I know it's a Dog; however, I'm getting an error when trying to read woof even after I checked the animal's type in the if statement.

On a similar note, I'd love to have an error if I try to add the wrong properties to an element in the array, e.g. { type: 'dog', actions: { purr: true } } (dogs don't purr).

How do I type-safely access the properties of an array element after narrowing on another property?

I'm not really tied to any of the code here, it was just my attempt at solving this problem. I'm getting the array of animals from the server, so I can't really change the actual data.

I'm happy to add any clarification if my question isn't clear.

interface DogActions { woof: true }
interface CatActions { purr: true }

type AnimalActions<T extends AnimalTypes> = T extends 'dog' ? DogActions : CatActions

interface Animal<T extends AnimalTypes> {
  type: AnimalTypes
  actions: AnimalActions<T>
}

type AnimalTypes = 'dog' | 'cat'

const arr: Animal<AnimalTypes>[] = [{ type: 'dog', actions: { woof: true }}, { type: 'cat', actions: { purr: true }}]

arr.forEach(animal => {
  if (animal.type === 'dog') {
    console.log(animal.actions.woof)
  } else if (animal.type === 'cat') {
    console.log(animal.actions.purr)
  }
})

CodePudding user response:

I would recommend for more questions start putting your code into TypeScript Playground and attach a link to your question. How about this?

interface DogActions { woof: true }
interface CatActions { purr: true }

type Animal = { type: 'dog', actions: DogActions } | { type: 'cat', actions: CatActions }

const arr: Animal[] = [{ type: 'dog', actions: { woof: true }}, { type: 'cat', actions: { purr: true }}]

arr.forEach(animal => {
  if (animal.type === 'dog') {
    console.log(animal.actions.woof)
  } else if (animal.type === 'cat') {
    console.log(animal.actions.purr)
  }
});

See it here working.

  • Related