Alright! Hello everybody! This video is a continuation of the previous video on basic types in TypeScript. Today we’re going to go over null, undefined, using types with functions, and a few other things. If you missed the previous video, you might want to go back and watch it before you start this one.
There was one thing I wanted to clarify from the last video. I mentioned that I strongly recommended against using the “any” type unless you absolutely had to, and I wanted to explain why. The basic reason, is that when you use the “any” type, you’re opting out of nearly all the checks that TypeScript is going to do for you, so if you’re going to use “any” everywhere, you might as well not use TypeScript.
I know when I first started with TypeScript, I often found myself reaching for the “any” type, but 99 times out of 100 it wasn’t because I needed it, but because I was being too lazy to stop and think about what the type of something should be.
If you take those few seconds to stop and think, you’ll end up with a program that’s better designed, you’ll have code that’s easier to come back to and change later, and you’ll have TypeScript helping you catch errors later on down the road.
You may be familiar with null from other programming languages, and the easiest way I find to think about null is that it represents the explicit lack of any value. To use our player object example, if there’s no player 2, it’s possible that we’d want our player2 variable to be null.
Undefined is very similar, as it also represents the lack of any value. The key difference here, is that any variable you never assign any value to is going to hold undefined by default (though you could also explicitly set a variable to undefined, like you can set one to null).
Generally, I see null as representing a value that is intentionally missing for whatever reason. Whereas when undefined crops up in a program, it’s often a mistake or accident rather than intentional, since it implys that somebody created a variable, but then never used it. Due to this, I recommend that if you need to indicate a lack of some value, use null rather than undefined, since it will be clearer to people interacting with your code that this was probably something intentional.
All that aside, how do we use null and undefined in our TypeScript programs?
You’ll remember from our last video that we could use “null” as a type just like string or boolean or anything else, and the same is true for undefined.
Notice that if we create a variable and don’t assign to it before we try to use it, TypeScript helpfully gives us an error.
Note also that even though variables default to undefined, we can’t actually assign the value undefined or null without specifying it as part of the type of our variable.
You’ll see we get the error “type undefined is not assignable to type string”.
We have to explicitly list it as a possible type in order for TypeScript to accept it.
You’ll see also that if we try to use this variable without checking wether the type is actually not null or undefined, TypeScript will give us an error as well, preventing us from making a common mistake where we assume a variable has been assigned some value, when really it could just as easily be null or undefined.
Now, it’s important to note that TypeScript actually has a mode where it will be less strict about the usage of null and undefined. If we open up tsconfig.json and scroll down a little bit, you’ll see that I have strict mode enabled. This enables all of the strict checks listed below it, but the one that is most relevant to us is “strictNullChecks”.
If we disable strictNullChecks, or if we disable all of the stricter checks, then TypeScript will become more lenient on us and allow us to set any variable to null or undefined.
Generally I recommend against taking the more lenient route, because it leads to a lot of potential errors where you assume something will have a proper value when it actually doesn’t. It’s much better to explicitly document using the type system that a value might be null or undefined so that the proper checks can be made.
Alright, enough of that. So far we’ve been defining a number of top-level variables, but your functions will need to have types as well in order to indicate the types of arguments they accept, and what values they return.
As an example, let’s create a super simple function that tests whether a given number is a magical number.
We’ll say that if the number we pass in is 5, then it’s a magical number, otherwise it’s not magical.
And you’ll see TypeScript is complaining at me here, saying “parameter num implicitly has type any”, which is a fancy way of saying I haven’t told it what type num is, so it is forced to assume that it could be anything.
We can remedy this using syntax identical to what we used above. After the variable name, I’ll simply put a colon and the type of the variable, which is number, and now TypeScript is happy with us again.
Not only is TypeScript happy with us, but if we go to use this function, our text editor can use the definition to display what the expected types of the function arguments are.
Another thing you can do is explictly specify what the return type of your function should be. We do this in nearly the same way as declaring variables, by placing a colon after the closing parenthesis and then the type.
So, for example, if we were like hey we should have been returning a boolean, we can specify that, and then TypeScript will let us know anywhere that we are returning the wrong value.
In general as I have said before, TypeScript is going to be really good at inferring what the types of things are. So, here we could have gotten rid of the return type and TypeScript would’ve correctly guessed that boolean was what we wanted.
However, I recommend you always type your arguments in your return values for functions, that way it’s really clear to you and your team members that the function is operating in the way you intended it to operate. And it’s really easy to just glance at the line of code where you create the function and get an idea of what you expect it to do.
One other type I wanted to mention that is related to functions is called the never type.
It’s an peculiar type that means a function will never return. The two main examples of this are functions that you call to throw an error, or functions that create an infinite loop.
For example, something you’ll see in many code bases is is a function named “fail” or “panic” or something similar. This is the function you call when things have gone horribly wrong and you need to log an error and end the program.
Since the program dies before the function fully finishes, the never type is very appropriate. It’s never going to return. You can indicate that this is the case for a particular function by specifying “never” as the return type.
Likewise, if you have a function containing an infinite loop, that will also have a return value of never. The loop never stops, so the function will never return.
Keep in mind that “never” is distinct from a function that returns no value at all. For example, many times when you’re working with graphics for a game or something else, you’ll have some code that updates those graphics on-screen. There isn’t much information this code needs to return anywhere, so it’ll successfully successfully draw the graphics, and then return nothing. For that case, TypeScript has a “void” type, which you can use to indicate that the function will return at some point, but it’s not going to return any value.
That’s it for how to use basic types, and that wraps up this video.
If you’ve enjoyed what you learned here, you might like the TypeScript course that I’m working on. Head on over to https://typescriptbyexample.com, and you can put your email address in a the bottom of the page to be notified when it’s ready.
Thanks so much for watching! See you in the next video.