Check out a free preview of the full Intermediate TypeScript, v2 course
The "null & Non-null Assertion" Lesson is part of the full, Intermediate TypeScript, v2 course featured in this preview video. Here's what you'd learn in this lesson:
Mike discusses the difference between null and undefined and introduces several TypeScript features and operators that can be used to handle nullish values, such as the non-null assertion operator. Examples and the potential use cases and limitations of these operators are also covered in this segment.
Transcript from the "null & Non-null Assertion" Lesson
[00:00:00]
>> The next topic we're gonna cover is Nullish values. These are dealing with values that might be empty or not yet populated. We talked a little bit about null undefined and void in terms of them being unit types. But let's talk about when it's appropriate to use undefined versus nuul and then we're going to get into a couple of topics here dealing with, how do you work with Nullish values?
[00:00:28]
How do you safely do that,TypeScript provides us with a couple different things,several operators here. All four of these are TypeScript features that have a particular syntax that you can use, that relates to handling Nullish values. So first let's look at null. So null differs from undefined in that null is something that has to be explicitly set.
[00:01:02]
So I tend to use null to mean that nothing is here. Like somebody has filled in this field and the field contains nothing null. It is distinguishable from undefined. Undefined, it indicates that something may not have ever been set in the first place. So, where are we gonna see undefined?
[00:01:30]
Well, anytime you have an optional property, right, on a, gosh, I don't even wanna say object type now, but on an interface, I can say that. Date has the possibility, or so completed at has the possibility of being a date or being undefined. And you can see here, if we're saying, all right, I've got a form in progress interface, I have a value that describes this form in progress.
[00:01:54]
And I want to then pass it into this, I wanna use it to submit this form. Sorry, let me get the tool tip here, it's lagging a little bit. Come on, give me completed at. So that is new date but if we look at the type here, it's still type form in progress.
[00:02:15]
This is gonna indicate that it's undefined, cuz that's how we've ended up with this. It's really coming from this type annotation here, right. It's gonna say, the value you gave me certainly meets this interface and if you want to regard it as this type of course. Sorry, I'm getting a little confused here, completedAt versus createdAt.
[00:02:39]
We could put a completed at here just for fun, I think the example still works. Yep, it does still work. So, yeah, we happen to be providing it in this case. We have both dates but here, if we're saying my date equals form in progress, whose type is the interface above, right?
[00:03:03]
It's the interface on line 11 which represents that completedAt may not be there. If we try to go ahead and grab it, it has the possibility of being undefined. So this is an interesting thing here. TypeScript has a new feature that we'll learn more about later called, it's a satisfies keyword which would make this a little bit neater.
[00:03:28]
It would allow us to say yes we have a form in progres, okay because onto that. But can you go ahead and keep the most specific type you can so that we don't lose the fact that completedAt. Is actually present it is present on this particular variable. So we'll learn more about that later.
[00:03:49]
That's undefined void. We talked about void just now. It means, a function functions return value should be uninteresting console.log is an example, don't listen to what console.log returns. All right, let's get into how we work with these Nullish values. The first of these operators we're gonna describe is the non-null assertion operator.
[00:04:15]
So here we have a GroceryCart. This fruits and vegetables, property, they both may not be present, right. So we're gonna create a cart called grocery cart. It happens to not have either of those two fields on it. And we can see that if we just try to go like cart.fruits.push, we're alerted to the possibility that cart.fruits is possibly undefined.
[00:04:42]
Adding this exclamation mark right here, that is the non null assertion operator. What this means is plow straight through. Does that sound safe?
>> It could possibly go wrong.
>> What could possibly go wrong seems like a great idea. It's not, it's not safe. It's not to say that this is useless, but this will error.
[00:05:06]
This will error, fruits is in fact not there, so this will throw. Now, where might this be useful? Well, I use this all the time in tests, why? I want things to throw, if they deviate from my expectations in tests. It's perfectly fine for them to throw, that is a test failure.
[00:05:31]
So it's a little bit like an assertion in a test. It works beautifully in tests libraries like MOCA, for example, where thrown errors are what happens when assertions fail. So if you have other thrown errors that are part of your test It'll be caught just like an assertion failure and in most cases it'll be surfaced very nicely.
[00:05:57]
There are test frameworks that don't behave that way, but I prefer I like when throws. Even if they're not part of a direct assertion, it's just like this function was not happy and it threw, I like that to be handled in a very visible way. Yes, sir.
>> Is that similar to that annotation you had already told TypeScript to ignore the next line, or is it more specific to just that one?
[00:06:20]
>> Very good question, yeah, we could do this. I could do that, so let's try that instead. Actually, I'm gonna leave this example, let's try it up here. So it would make that error go away, but what about this Oops, I'm lagging a little bit here. Should this work?
[00:06:55]
There's a difference between turning TypeScript off and saying specifically, please just ignore the possibility that this one thing might be null. So that's part of the value here, you don't want to sort of say TypeScript literally get out of my way on this next slide like don't do any type checking, don't error I don't care what it is.
[00:07:22]
Versus this is a much more precise way of saying just that I want you to ignore something very specific and it's the possibility that this one thing is null. And if you had, let's say cart could have been undefined, you'd have to add a bang, an exclamation mark, every step of the way that you wanna plow through a specific possibility that something is undefined.
[00:07:46]
So if it were a chain, sometimes you have a big nested JSON object, and it could be a bunch of things, and if you just wanna sort of plow straight through into a particular path. You'd need a lot of exclamation marks in order to do that, but that would be perfectly fine in a test, right?
[00:08:01]
Where you get the result of a function and you want to know, did some, grandchild object have a particular field on it with a value you could just push straight through. And if anything throws that's an assertion failure, that's great. But I tend to not want to use this in library code or an application code because it's dangerous.
[00:08:24]
I'm about to talk about one place I will use something very similar. It's similar in nature, it's kind of the same syntax, also an exclamation mark. But we'll get to that immediately, let me just get this back to where it was, all right.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops