Home > Software design >  Type Narrowing Not Working On Parent Object
Type Narrowing Not Working On Parent Object

Time:08-14

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);
  }
}
  • Related