Reputation:
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
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
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