Check out a free preview of the full TypeScript Fundamentals, v3 course:
The "Optional Properties" 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 demonstrates how to state optional properties for objects using the ? operator and discusses the difference between optional properties and properties that have the option of being undefined. A demonstration of TypeScript throwing an excess property error, why the error exists, and how to handle the error is also provided in this segment.

Get Unlimited Access Now

Transcript from the "Optional Properties" Lesson

[00:00:00]
>> So what about optional properties? Let's extend our model of a car and we'll say, sometimes we have an electric car and they wanna charge at a particular voltage. So what is that chargeVoltage? Is it 240 volts, what is it? Now, chargeVoltage doesn't make any sense for a car that runs on gasoline.

[00:00:23] So, Let's say that for electric cars we will find this value, but for non-electric cars this value will be missing. So this is an optional property that may or may not be there. It's sometimes there, and it's a number. So we're going to use this question mark to state that chargeVoltage might be there, but if it is there it will be a number.

[00:00:54] And if we hover over this, the type of chargeVoltage, its number and then a pipe and undefined. Can someone make a guess as to what the pipe means? When do we see a pipe in JavaScript? Maybe two pipes next to each other.
>> Means or?
>> It means or, very good.

[00:01:16] So you can think of this as or for types. I see a lot of people in the chat got it as well. So we'll talk more about and and or, it is possible with types. But here we're seeing something that conceptually aligns with what we set out to do.

[00:01:30] And that is, it may or may not be there. So here we can see we regenerate our string. Here's our chargeVoltage, and this is interesting. So, what we're doing here is we're gonna make a basic string, and then I've just put this line here to kind of reveal the type of chargeVoltage that has this undefined.

[00:01:57] And then we have this condition. And at run time, if we think about what this will do, we're checking to see if chargeVoltage is defined or it's not. So we're creating a branch of code that will only execute if something is there for chargeVoltage. And sure enough, we can see that we've eliminated the undefined possibility here, right?

[00:02:24] If we go down this branch of code, TypeScript seems to be able to understand that we're gonna have a number there, and we can use it. We can print it as a number, right? This is what's called a type guard. It's where you typically will combine some sort of predicate, like a check true or false expression, right?

[00:02:50] You'll combine that with some control flow tool like if or a case switch. And in doing that, you'll create branches of code where the compiler can understand that like we'll take a left turn if we're undefined, and we'll take a right turn if we are defined. And that allows you to kind of consume these things safely.

[00:03:17] By the way, this is one of those key points I talked about where people love TypeScript. Every time I convert a JavaScript code base to TypeScript I find a bunch of these, where somebody was sort of betting on this value will probably be there. And it turns out, there's no code that guarantees that, TypeScript is gonna demand that we put this line here in order to start using it.

[00:03:39] We can go out to the playground and give this a shot. So if we were to take this away, and let me make this a little bit more obvious, we'll say, toFixed, right? So I'm just trying to use this in a way that's gonna really break if it's something other than a number.

[00:04:03] If we got rid of this type guard, it's just gonna say, look, you can't do that. This could be undefined, you can't just reach into it and call toFixed. So the type guard serves that purpose. And I guarantee you write JavaScript code today that is missing these in important places.

[00:04:24] I know, I do it all the time. Like every time I convert, I find a bunch of these. So, because we have this optional property, we can either pass this value in as we are down here, or we can omit it. Now, some of you may wonder what if here, For this chargeVoltage, what if I did this?

[00:05:00] And let's try to use it. So something's not happy here. And if we look at this error, it's a little hard to read. I read TypeScript errors from the bottom up cuz they're kind of like stack traces, especially in this case where we have a problem with the whole object.

[00:05:34] That lowest line and the error message will tell you the property that caused the problem. So we're seeing, okay, chargeVoltage is declared here, chargeVoltage is missing in type, and then it lists the type, but it's required in type, and then it lists another type here. So what we're saying here is if I didn't have a chargeVoltage, I actually have to do chargeVoltage is undefined.

[00:05:58] I have to pass in an undefined, that's kind of weird. There's a difference between an optional property and a property that has the potential to have an undefined value. Optional properties can be left out, but if you do this, someone's gonna have to pass an undefined, which is really weird.

[00:06:19] I don't like passing undefined in as a deliberate argument, right? That's kind of strange, or deliberate property value. So, that's the difference. And I see some face palms in chat. This is a justifiable facepalm. So, yeah, you wouldn't be able to do this. So optional is more than simply adding that or undefined.

[00:06:45] It means that it can be present, it can be absent. There is another type of error that TypeScript catches for us called excess property checking. And again, I'm gonna illustrate this with an example that builds potentially one more thing onto our car model. So we have our make, model, and year.

[00:07:06] And let's say that someone got really eager and they decided they want to describe the color of their car and pass that into this function. So we're getting what's called an excess property error, and the keywords to look for here is object literal may only specify known properties right here.

[00:07:34] And color is not one of those properties. So it's saying, you gave me this thing and I didn't ask for it. And if we eliminated it, everything would be fine, why? Why is TypeScript mad at us? This won't break your code. The fact that red's there won't break your code, so why are we being alerted?

[00:07:55] Well, If we started to use car in here, there's no way to safely access that color property. So it's a case where when we're changing, when we have that color property there, we're setting ourselves up to never be able to safely access that extra thing. It's like an appendix, it's this vestigial thing that serves no purpose can safely be eliminated, we know conclusively.

[00:08:26] So there are a couple things we could do if we wanted to handle this case, and I'm going to show you a couple of them. First, we could certainly say oops, we can make it optional. This would make this thing go away cuz potentially in here, we could use the undefined check, we could access color, it's no longer a pointless thing to pass in.

[00:08:52] So that's one thing we could do. And here's another thing that sort of makes the point as to how the compiler is trying to help us. Let's, myCar, let's give it a value, or variable, rather. So here, we're also not getting an error, why? Well, conceivably, something else other than printCar, could reach into this my car thing, And get color.

[00:09:23] That's totally fair. It's no longer definitely pointless to have that color property on there. And when we talk about object literal, like access object literal property checking, it had to do with the fact that we were just passing this thing in directly to the function as an object literal.

[00:09:46] And that's why we were guaranteed that like nobody is ever gonna be able to make use of this color property. No one else has access to it. It just lives in the argument list of this one invocation of print car. It lives in a stack frame. And so definitely no one else is gonna be able to use it.

[00:10:10] So you will see errors like that when you convert something from JavaScript to TypeScript, and you'll solve it a number of ways. As you're doing your early conversions, it's gonna be because your types were missing something like, yeah, color, we need to handle color. And then you're gonna start to find things where there's like a misspelling or something weird.

[00:10:31] So we saw three different ways to solve this. Remove the property, add the property to the type, or create a variable. Because conceivably, something else could access color through that variable.