in typescript 2.6 I want to write a function that does a null check. When I enable strict null-checks, typescript 2.6 complains about the following code. (Note that when using the null check directly works)
edited: corrected notNullOrUndefined since it didn't check for foo
interface A {
foo: string | undefined;
}
const notNullOrUndefined = (a: A): boolean => {
return a.foo != null;
}
const len = (a: A): number => {
//if (a.foo != null) {
if (notNullOrUndefined(a)){
return a.foo.length;
}
return 0;
}
here is the example to play with: example
What's the typescript way to solve this?
EDIT: updated to reflect fixing a typo in question: The question is a little confusing, since your notNullOrUndefined() doesn't check a.foo at all, so it's not surprising that those would be different.
Note that with --strictNullChecks on, you have defined len() so that the a parameter is an A, and therefore cannot be null or undefined. So you don't have to check a itself inside the len() function implementation; instead you need to make sure that anything you pass to len() is a valid A. So notNullOrUndefined() is kind of a bad name, since you're checking the foo value of the parameter, not the parameter itself. Feel free to change it to something like fooPropertyIsNotNull(); I will leave it for now.
The main issue here is that TypeScript recognizes that if (a.foo != null) { ... } is a type guard, and narrows a.foo to string inside the { ... } clause. But type guards do not propagate out of functions automatically, so TypeScript doesn't understand that notNullOrUndefined() itself acts as a type guard.
Luckily, this issue is common enough that TypeScript provides user-defined type guards: if you have a function that returns a boolean which narrows the type of one of its parameters, you can change the boolean return type to a type predicate, using the x is T syntax. Here it is for notNullOrUndefined():
const notNullOrUndefined = (a: A): a is { foo: string } => {
return a.foo != null;
}
So the function signature says: if you pass in an A, it will return a boolean value. If it returns true, then the passed-in parameter is narrowed to { foo: string }. Now you will get no errors, as you wanted:
interface A {
foo: string | undefined;
}
const notNullOrUndefined = (a: A): a is { foo: string } => {
return a.foo != null; // checking a.foo
}
const len = (a: A): number => {
if (notNullOrUndefined(a)){
return a.foo.length; // okay
}
return 0;
}
Hope that helps, good luck!
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