Janosch Hübner
Janosch Hübner

Reputation: 1694

Typescript functions that check for null / undefined

I am using VS Code and it helps a lot when working with Typescript as it tells you when current issues there are without needing to transpile. I am using Typescript with nodeJS and it works really well.

The only issue I have is so called "null / undefined checking functions".

See this example:

class User {
   public someProperty: string | undefined;
   // ...

   public get canDoSomething() {
      return this.someProperty != undefined;
   }
}
let myUser: User = ...

This works nicely:

if (myUser.someProperty != undefined) {
   // at this point myUser.someProperty is type string only (as it cannot be undefined anymore
}

However this fails

if (myUser.canDoSomething) {
   // because typescript still thinks that myUser.someProperty is string | undefined and not just string, even though this method checks for that.
}

Any idea how I would tell typescript? Because sometimes a method like that is cleaner than keep comparing the properties to undefined itself.

Thanks

Upvotes: 4

Views: 1335

Answers (2)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249706

Type narrowing works with specific syntactic constructs. if (obj.prop != undefined) is one such construct, that will inform the compiler prop can't be undefined.

In your case you perform the check in a property. Typescript will not follow the implementation of the getter to see that it performs the null check.

You could use a custom type guard (a method/function with special syntax that informs the compiler of type side effects) :

class User {
   public someProperty: string | undefined;

   public canDoSomething() : this is this & { someProperty: string} {
      return this.someProperty != undefined;
   }
}
let myUser: User = new User

if (myUser.canDoSomething()) {
    myUser.someProperty.big()
}

I would recommend with sticking with the simpler if (myUser.someProperty != undefined) though unless you have a good reason to encapsulate the check.

Edit

this is this & { someProperty: string} informs the compiler that the type of the object this method was invoked on (this) has now changed (is) to a new type (the intersection this & { someProperty: string}).

this in the intersection this & { someProperty: string} acts as the type for the current class (called polymorphic this) and will be either User or any class that derives from user (could have used User instead of this but it would not have worked on derived classes.

The intersection (&) with { someProperty: string} will mean that the type after the check is both whatever class we had before (this) and an object with a property someProperty of type string. Since User already had someProperty the type of someProperty in this intersection will work out to User['someProperty'] & string = (string | undefined) & string = stringefectively removing undefined from the type of someProperty in the resulting type.

Upvotes: 6

Alexandre Fradette
Alexandre Fradette

Reputation: 372

You might want to changed:

myUser.someProperty != undefined

To

typeof myUser.someProperty !== "undefined"

This will check the typing instead of the value.

Upvotes: -1

Related Questions