I have a general interface which I use to define properties (let’s say it’s an Animal).
Then I have extensions of this interface, which have additional different fields.
I want to define a function that gets an instance of an animal, spreads it – and parses a specific field.
The result value should be the same as the input’s; however I get an error, as not all animals are equal 😛
How can I use the spread operator and still return the same type?
interface AnimalProps { name: string; size: string; }
class Dog implements AnimalProps {
name: string;
size: string;
bark(): void { console.log(`${this.name} says: 'woof'`); }
constructor(name: string, size: string) {
this.name = name;
this.size = size;
}
}
class Bird implements AnimalProps {
name: string;
size: string;
fly(): void { console.log(`${this.name} says: 'I love flying'`); }
constructor(name: string, size: string) {
this.name = name;
this.size = size;
}
}
type Animal = Dog | Bird;
function addSizeUnits(animal: Animal): Animal {
// Property 'fly' is missing in type '{ size: string; name: string; }' but required in type 'Bird'.
return { ...animal, size: `${animal.size} meters` };
}
Obviously I’m simplifying the existing (legacy) code here, but the bottom line is that I do need to use fly and bark and therefore I need the actual union types – and not the basic Animal.
>Solution :
A generic function should work here. Something like:
function addSizeUnits<T extends Animal>(animal: T) {
return { ...animal, size: `${animal.size} meters` };
}
Note that I removed the return type annotation because the type inference should figure that out for you, but if you want to add it back you can use something like correction, just T & { size: string }T should be fine because you already have size in AnimalProps.