user10968967
user10968967

Reputation:

Changing a variable's type in TypeScript

So here's my problem, let's say I have some types of animals:

interface IAnimal {
   type: string;
   legs: number;
}

interface IChicken extends IAnimal {
   eggsPerDay: number;
}

interface ICow extends IAnimal {
   milkProduction: number;
}

...

doSomethingWithAnimal(animal: IChicken|ICow): void {
    switch(animal.type){
        case 'cow':
            alert(`the milk production is ${animal.milkProduction}`);
    }
}

The problem that I have is typescript doesn't know if it's a cow or a chicken. Is there a way that once I know for sure that the animal is of type ICow that I can safely access those additional attributes?

I know that it's possible to do const cow = animal as ICow but wouldn't that needlessly copy my variable? The example that I provided is an oversimplification since the problem that I'm actually trying to solve has ten derived classes and the function is called a ton, so I want to keep it as efficient as possible.

Upvotes: 5

Views: 116

Answers (2)

dileepkumar jami
dileepkumar jami

Reputation: 2265

You can try below,

  doSomethingWithAnimal(animal: IChicken | ICow): void {
    if(animal.hasOwnProperty('eggsPerDay')) {
      console.log('eggsPerDay', animal.eggsPerDay)
    } else if (animal.hasOwnProperty('milkProduction')) {
      console.log('milkProduction', animal.milkProduction)
    }; // other conditions
  }

StackBlitz code for reference

Upvotes: 0

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250316

You can use a discriminated union for this task. You just need to add a type member to each memebr of the union with the actual type as a string literal type:

interface IAnimal {
  type: string;
  legs: number;
}

interface IChicken extends IAnimal {
  type: "chicken";
  eggsPerDay: number;
}

interface ICow extends IAnimal {
  type: "cow";
  milkProduction: number;
}

function doSomethingWithAnimal(animal: IChicken | ICow): void {
  switch (animal.type) {
    case 'cow':
      alert(`the milk production is ${animal.milkProduction}`); // ok now
  }
}

Upvotes: 3

Related Questions