Check out a free preview of the full TypeScript Fundamentals, v3 course:
The "Variables & Values" Lesson is part of the full, TypeScript Fundamentals, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Mike discusses simple let and const declarations, literal types, demonstrates TypeScript throwing a type error, implicit any, and adding type annotations. Defining function arguments and return values are also covered in this segment.

Get Unlimited Access Now

Transcript from the "Variables & Values" Lesson

[00:00:00]
>> Let's talk about variables and values. In this chapter, we're gonna talk about simple let and const declarations and the very basics of typing functions. And that will serve as a good foundation for us to start building other more complicated types on. So variable declarations in JavaScript, kind of look like this, right?

[00:00:21] We have let and const hopefully nobody's using bar anymore, but we can just say something like, let age = 6. And you may note that TypeScript is kinda figured out this is a number. This does not seem like an impressive trick, because obviously 6 is a number, right?

[00:00:40] Well, what you're seeing is inference, where TypeScript can contextually understand the situation. It can see that yes, we have a variable declaration with an initializer, right? Where we're assigning it to 6 right away, clearly that should be a number, right? And not every programming language has this by the wa,y if you work in the Java or the C++ area, every variable declaration typically comes with the type up front.

[00:01:11] You have to say like int age =6, you'd have to say it's an IT. This up here seems like regular JavaScript. But down here, you could totally do this with JavaScript, but TypeScript is unhappy, why? Age was the variable that was born with a type and that type is number.

[00:01:31] And we can see that if we attempt to give it a value that's a string, it's going to yell at us. This is the kind of thing that TypeScript is designed to catch. I want you to remember that in TypeScript variables are born with their types. So there are things we can do, which we'll learn about later to make these types more specific.

[00:01:54] But it's hard to make them more general, once they're declared. So, it's important to make sure that when you define your variables, they have the types that you need them to have. And if you ever need to generalize them, usually you go right back to that variable declaration, and that's where you have to make a change.

[00:02:13] So let's look at a similar example, but with const. So if we just change our let to const, we can see that we get a different type here, and that type is 6. And you might think, well 6 is a value, right? Number is a type 6 is a value.

[00:02:29] What we have here is called a literal type and it's a more specific kind of type. It's not just any number, it's any number that is 6. You can think of it that way, right? So the reason that changing let to const has done this thing, that we see before our eyes has to do with two things going on.

[00:02:56] One, it's the nature of const's declarations, they can't be reassigned. So we know that once we point it at a thing, it will forever pointed that thing, age will always point to whatever it is assigned to. And then the second is that, numbers in JavaScript are immutable value types.

[00:03:17] Unlike arrays, where that's a value type where you can push things into it, right? 6 will always be 6, right? We can create a new number, but we can't change an existing number. So basically, this whole thing is poured and concrete, where it's a variable that can never point to something else.

[00:03:39] And the thing it currently points to cannot change. So we know very specifically that this is 6 and it will always be 6. So TypeScript can make a safe more specific assumption here. And that's a theme we're going to see over and over, by the way, where TypeScript tries to make the most specific assumption, that it can without risking getting in your way.

[00:04:06] So 6 is called a literal type, meaning it is literally the number 6 and if we think about why we were able to make this assumption more specifically, like we said in our two reasons there. But imagine if we made that same kind of very specific assumption with a let declaration.

[00:04:29] So if we go back up here, what if we assumed age was always going to be 6 that would get in our way, right? Like the nature of let declarations we're probably going to assign them to something else in the future. And that's why you get that the more relaxed constraint there, where normal code that treats this as a number is going to behave nicely, right?

[00:04:52] Don't want TypeScript to get into your way. We're gonna see literal types over and over, but you can just think of them as a set of allowed values. So sometimes we end up in situations where we have to declare a variable, and then the variable gets its value sometime later.

[00:05:17] So let's look at this piece of code which begins with a timestamp, and it ends up measuring a startTime and then sometime later when it finishes a random wait, and it record an endTime. So maybe we wanna have access to this endTime in this outer scope. But clearly like within this set timeout function, that's when it's actually going to get its endTime.

[00:05:48] So you could end up with something like this. And if we look at the way this is defined, we can see that this is of type any that's what this notation means, by the way. EndTime is a variable, it's a let declaration and it has a type called any.

[00:06:04] Any is the most flexible type in TypeScript. And you can think of it kind of like JavaScript variable rules, where we could set it equal to a string and then a number and then a function and then null and then whatever, there's no constraint. It can be anything, any value that is allowed in the JavaScript world.

[00:06:28] So it's not necessarily bad, but it's often much more flexible than what you want. And in this case, we can see that there's just not enough information for TypeScript to make a guess as to what this should be. Because types are assigned to variables when those variables are born.

[00:06:49] And when this is born, we don't know when the set timeout is gonna be invoked, and we don't know what value it's going to get. So in this case, we need to add what's called a type annotation. And that is our colon type syntax, right? Where let here, what we're saying is, endTime is a Date, we're not giving it a value yet, but it's going to get a Date and you should treat it as if it's going to get a Date.

[00:07:22] And now when we for some reason we're setting this to = to 0 before we give it its real endTime. We're told that we can't give it a number. This is a slot that's designed for a Date. This is exactly what we should give it. So now we're seeing enforcement of types.

[00:07:40] I only add type annotations like this when I have to, because it's just extra stuff in your code, and it tends to make things a little bit more difficult to refactor. If you start adding types all over the place, but in this case it's absolutely appropriate and absolutely necessary.

[00:08:00] So let's look at functions. This same syntax that we saw with this variable up here, right? Colon Date this can be used with our add function here that we saw in the first slide of the course. It can be use to state that a and b are numbers.

[00:08:20] And this function add returns numbers. You can see that by default, everything ends up being any. This is because like imagine we were converting this from a JavaScript file to a TypeScript file. Maybe we start with everything loose and then we wanna crank things up and define the types as we go.

[00:08:40] That's probably not what we want in the end now, right? So why is any gonna be a problem in this case? Well, look here. This we know is gonna be 7 based on the implementation of the function a+b. So we know promise doesn't accept 7 as its constructor argument, but TypeScript seems to be happy about this.

[00:09:05] This is not the same point that I was making before, where the return value doesn't have a type and therefore we could use it. We can reach into it in unsafe ways. If you have an any that's floating around. If that value enters well typed code, it will break that well typed code, so the guarantees I have around promises don't matter right now.

[00:09:27] Because I have this any, so having something like this floating around can weaken your guarantees that you have around your code. It's kinda dangerous thin, now I say dangerous. It's only as dangerous as a regular JavaScript variable, which is dangerous. So let's add some type annotations here. We can say that a and b are arguments, each of them is a number.

[00:09:52] And here it's very clear that the result that's returned is a number. And if we attempt to use this, I mean, we already saw this example, we can't pass a string in that's not compatible with a number. You may notice that, the return type of the function is also inferred so that number on the right side of the tooltip, the compiler is smart enough to figure out that a + b, the result of adding those numbers together is a number and that's what's returned.