I have this code sample:
type Dog = {
legs?: number;
};
function printDogLegs(dog: Dog) {
if (dog.legs !== undefined) {
printConfirmedDog(dog);
}
}
type ConfirmedDogWithLegs = {
legs: number;
};
function printConfirmedDog(input: ConfirmedDogWithLegs) {
console.log(input);
}
Despite the typeguard, I get this error from the TypeScript compiler:
TS2345: Argument of type 'Dog' is not assignable to parameter of type 'ConfirmedDogWithLegs'.
Types of property 'legs' are incompatible.
Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
212 | function printDogLegs(dog: Dog) {
213 | if (dog.legs !== undefined) {
> 214 | printConfirmedDog(dog);
| ^^^
215 | }
216 | }
217 |
I would expect TS to narrow the type of Dog
from legs: number | undefined
to legs: number
. Why is this not the case? And how should I go about solving this problem?
CodePudding user response:
The thing is that if (dog.legs !== undefined)
doesn't infer that dog
is of another type, but that dog.legs
is just number
(without undefined
). It continues to be of type Dog
.
That's why Type Predicates exist in the first place. A Type Predicate
function would solve this by narrowing the object type to something else. It would be like the following:
function isDogWithLegs(dog: Dog): dog is ConfirmedDogWithLegs {
return dog.legs !== undefined
}
and the check is going to be like this:
function printDogLegs(dog: Dog) {
if (isDogWithLegs(dog)) {
printConfirmedDog(dog);
}
}