As JavaScript developer I'm new to type checking and I struggle to understand why this simple code is not working:
type Animal = {
id: number,
name: string,
type: 'dog' | 'cat'
};
type Dog = {
id: number,
name: string,
type: 'dog',
color: string
};
function printAnimal(animal: Animal): string {
return `${animal.type}: ${animal.name}`;
}
const buddy: Dog = {
id: 1,
name: 'Buddy',
type: 'dog',
color: 'black'
}
printAnimal(buddy);
What I'm trying to achieve here is to have a method that accepts interface. This however gives me error: Cannot call 'printAnimal' with 'buddy' bound to 'animal' because string literal 'dog' [1] is incompatible with string literal 'cat' [2] in property 'type'.
.
What I tried:
interface Animal { // ...}
- does not work.buddy
- it work's but I'm not satisfied. Sometimes I do want to have more strict type (so I know I'm dealing with dog not cat) but still use general method that accept any animal.type: 'dog' | 'cat'
to type: string
- does not work. I would expect 'dog'
string is subtype of general string
type but it's not. On the other hand even if it works it wouldn't be enough - sometimes I know that my app accepts only dogs and cats not any other animals.Thanks for reading and I hope I can get some help from you guys! Here's live version: Try Flow - live example
You have to make the Animal
type an interface since it's describing your types implementations as a "parent". And it would make sense if you enforce it by extending your Dog
type via a union since that's the point of using typings to reach a stronger type-checking.
This can be written like this:
/* @flow */
interface Animal {
id: number,
name: string,
type: 'dog' | 'cat'
};
type Dog = Animal & {
type: 'dog',
color: string
};
function printAnimal(animal: Animal): string {
return `${animal.type}: ${animal.name}`;
}
const buddy: Dog = {
id: 1,
name: 'Buddy',
type: 'dog',
color: 'black'
}
printAnimal(buddy);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With