TypeScript 5+ Fundamentals, v4

Variable Declarations & Inference

TypeScript 5+ Fundamentals, v4

Check out a free preview of the full TypeScript 5+ Fundamentals, v4 course

The "Variable Declarations & Inference" Lesson is part of the full, TypeScript 5+ Fundamentals, v4 course featured in this preview video. Here's what you'd learn in this lesson:

Mike discusses the use of variables and their types. The difference between `let` and `const` declarations, literal types, type annotations, the concept of sets, and how types represent sets of allowed values are covered. This segment concludes with an example of an implicit `any` type and how to use type annotations to provide explicit types.


Transcript from the "Variable Declarations & Inference" Lesson

>> For the remainder of this course, we're gonna work in another package within this repo. And it's a notes package, so the point here is really to have examples of TypeScript code that we can poke at. We may try to build it at times, but it's mainly just so we have an authoring environment that we can share.

It matches what we're gonna be looking at on the website, if we go and look at the website, it's gonna be each code snippet that you're able to see there. So you're going to go to notes TS fundamentals v4. We're gonna open up this source folder, and you can see for every chapter of this course we have a notes file.

In JavaScript, you're familiar with this concept here, right this is a variable declaration. We're using let here, and let would allow us to reassign this variable, right? And if we hover over this word temperature. Well, we're being told we haven't used this variable, but we'll use it in a sec, but we can see let temperature, colon number.

So what we're seeing here is TypeScript has inferred that this is a number based on us just saying that we're initializing this variable to 6. It knows that we're dealing with numbers here, and what we get here is type checking. So TypeScript said okay you initially gave me this number 6 and now I'm going to try to use the string warm and TypeScript objects it says string is not assignable to type number, what we're seeing here is that variables are sort of born with types.

Meaning, if we have something like this, and temperature is a number, there's really nothing we can do to make this variable accept a different type. There are things we could do on this line that will make it initially be created with a different type. But once it's created, a variables type can never change.

Let's try the same thing with const. So, can somebody tell me in the classroom like what's the difference between a const declaration and a let declaration? Go ahead.
>> It const is constant so you can't change the value.
>> You can't reassign the variable common misconception that you can't change the value, so in this case it's actually both 79 is a number, and in JavaScript that's an immutable value type.

We never change numbers, we can only create new numbers. So here we have non re assignability coming from const, but we also have immutability coming from 79. As opposed to if we made this an array like this, we can certainly change the value, we can push more things into the array, right?

It's not like it's frozen in place, the variable always will point to that array, but we can change the array in place. We can't change this number in place, we can't make it 80. So, let's look at the type of this, const humidity79, 79 in this context, it's not a value, it's a type.

TypeScript has noted that we have an immutable value type. And we can never reassign this variable humidity can never be anything other than 79, we could assign it or we couldn't assign it to something new like it's only the number 79. So I want you to start building a little bit of a mental model here based on sets.

Does everybody know what a set is? It's like a group of values where there are no duplicates in the list of values, so you could think of types as describing a set of allowed values. So, of course a let declaration lets us reassign given a different number. We can actually take this 79 that we had in humidity, and we could set the temperature equal to 79, right?

There's no problem with that, temperature will accept any number. Now what we can't do, while for a variety of reasons but we can't take temperature and assign it to humidity because humidity is a constant. Yeah, we're gonna have to make this slightly different, and I'll explain why in a moment.

So I'm making this a let declaration that sort of allows us to have re-assignability, but it's typed is still 79. I'm doing something here called casting where I'm saying, I have value here, this is the type I want you to regard this value as. So here we can see number is not assignable to type 79, and if we think about this in terms of sets.

Humidity is allowed to be any number as long as it's the number 79 It's only got one thing and it said it can only accept 79s on this line 13 You can see it's perfectly happy to accept a new number 79 like this is in a different place in memory Than this original 79 here.

So we are assigning it a new number, but it must be exactly the value that we gave it before, it must be just that one value. Here, we're seeing that we can't just take an arbitrary number and put it into a slot that only accepts 79s, because of course, they're all of the other numbers, right?

We can't ensure that there's compatibility there, so we would say this is a very general type, and this is a very specific type. And here's an example of us trying to put a specific value in there, 78 is not a 79, but if I change this, it would be fine.

So what we would call this here, it's a literal type, and that means we're using a value and creating a type that represents only that one value. We could do the same thing with the string if we wanted to. String is also an immutable value type, const does not allow us to reassign.

So those two facts mean this will always be foo, right? So that's called a literal type, and I'm going to put this back to const. Let's think more about types as representing sets of values. So if we create another variable here, we're calling it temp2, we're setting it equal to 19, the type of temp2 number represents the set of all numbers, that's what I'm using these little braces for here.

If we use this as const casting here, we're basically saying, I want the mutability of let, but treat it in terms of obtaining its type as if it's a const, right? And you can see we get that 79 here, just as above where we were saying like 79 as 79.

This is kind of the same thing, except it's saying, instead of saying the 79 type again, we're just saying treat it like it's a const in terms of inferring its title. So now we have a lead declaration that's also just containing this one thing. When we're doing something like this, anytime we see an equal sign, we're performing what we call a type equivalence check.

And that means, can the type of the variable or function parameter or whatever it is, on the left side of the equals, can that hold a value of the type on the right side? So can a number, something that wants a number, will that be happy if I give it a 79?

Sure. But if I have something that only accepts 79s, I can't just give it any arbitrary number, it only wants that one specific number. Does this make sense, thinking about types in terms of the values that type will accept.
>> So could you do let humidity equals 10 as 79

>> Let's try that You could, don't do this. You could this is like, I described this as casting, a lot of languages have this concept of casting. When you do casting, you're effectively telling the TypeScript, you know better, there's telling the type checking system you know better, irrespective of what this value is.

Well, in this case we're gonna get an objection here, because there's even more incompatibility. But you're telling it, I know what I'm doing, please regard this as this other type, it's really sort of a heavy-handed way to override the safety that typescript would normally give you. Now, this is why it's sort of preferred to do this, because it ensures you get like a valid type that fits this value It's just a very specific type, but it will always be valid you're just telling typescript to be more bold in its assumptions that like it's not just any number.

It's specifically the number 79, what TypeScript generally tries to do is make the most reasonable assumption it can make without getting in your way. So if every let declaration like this turned out to be specifically the type 79, like that would interfere with our ability to use let's the way we normally use let's.

This is why we see the behavior change when we switch to const, because it can make safely a more specific assumption without getting in your way. So sometimes we need to declare a variable before it's initialized. And let me uncomment the next section here. So in this example, we have sort of a time interval, that's what we're trying to model here.

So we have a random wait time up at the top, we generate some random value. We have a time interval, we know the start time, because we're running this code, and then we initialize start time, we get a new date. That is like right now, at the moment, that date invocation, that date instance is created, endTime we're gonna fill in later, right?

We need to wait however long this random wait is. And then we'll know what the endTime is, and what we can see here is endTime, because we don't initialize this variable, it is of type any. We would call this an implicit any, any, you can think of as a type that represents the way variables work in JavaScript.

You could take this and you could make it a function, or you could then pass it a number, you could then give it an HTML input tag, and it would be happy to accept all of these things, right? Any is ,we'll talk more about this in the intermediate TypeScript course, but we would call this a top type.

It can accept absolutely any value that is possible to create in JavaScript. But this isn't what we want, even once we assign end time its date in the end, we lose type information here. So we talked about any why is this an implicit any? It's implicit because we haven't stated a type here, but TypeScript cannot obtain the necessary information in order to know what this should be.

And so effectively anything TypeScript can't figure out, it will type as any, at least with the way we have the compiler set up right now. We can change this though, we can give this what's called a type annotation. And we've already seen this, we saw this in our our hello world TypeScript program.

We're gonna add a colon and then date. See how it says interface date? This is the type of a date instance. And down here you can see all right, well we're being busted now we're setting endTime =0. While it should be a date, this is a line of code that shouldn't have worked like in regular JavaScript this would have worked we might not have noticed this.

But now if we had some function that would like measured the start and the end time and give us a very human-readable time interval, how many seconds is this? How many it would format it properly like now we know we're not gonna work with a number here we will always have a date and a date both of these end up being dates this one up here start time gets it because of how we initialize the variable and here we have this explicit type annotation.

And you'll see this pattern all over the place, it works for function parameters, it works for function return types for class fields, it's just colon and then the name of the type. So we can delete this because, that's a bug, and we'll move forward

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now