Check out a free preview of the full TypeScript 5+ Fundamentals, v4 course:
The "Objects & Property Types" 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 explains the concept of objects in JavaScript, how to define their types in TypeScript, and demonstrates how to create an object type and use it as a function argument. Optional properties, type guards, and how excess property checking prevents passing in unknown properties to an object are also covered in this segment.

Get Unlimited Access Now

Transcript from the "Objects & Property Types" Lesson

[00:00:00]
>> Next we're gonna talk about objects arrays and tuples, so in JavaScript you're familiar with creating an object for something like a car that looks like this. Right, you got to make a model any air three properties. The first two are strings, the last one is a number.

[00:00:28] We have an equal sign here, that's the assignment, right? And if we hover over this you can see TypeScript is telling us what the type of this value is. So object types, just like objects, are wrapped in braces, and the key thing to look for is this colon.

[00:00:45] That's how you know we're not doing an assignment here, an initialization of this property. We're simply stating its type. So previously in the last chapter when we were doing colon date, this is something very similar except we're describing the type as an object type like this. You can have field names here.

[00:01:06] And then types that are you know the type that you're willing to accept for each field name. Note that you don't need commas here you can use semicolons if you want depending on your preference for using semicolons in other areas of your JavaScript code base. But this is our first example of an object type.

[00:01:28] So we could create a function that uses an object type to describe its argument. Okay so here we're saying we have a function called print car we take an argument called car whose type is this make model year thing. And then we when we run console.log you can see our autocomplete is telling us these properties are available when we hover over each of them you can see make is a string, model is a string, year should be a number, right?

[00:02:02] So this is what lets us safely use these properties within the function if we did this We would say, flat tires is not a thing on cars, so this is more value that TypeScript is giving you, right? You get to state up front what this thing has, and you will be alerted to any use of something that's not defined on the type.

[00:02:33] So we're getting an error saying car is used before it's being assigned. Let's just do this. We'll set equal to my car. And now the function's happy. So TypeScript knows whether variables have been initialized or not, and it will. Warn you if you're trying to use it before it was set to something.

[00:02:58] So what if we wanted to introduce as part of like an electric car feature. We wanted to introduce the concept of a charging voltage. I don't have an electric car, but I assume they have different charging voltages like for fast charge and slow charge something like that. Let's pretend them right

[00:03:21]
>> 110 or 221?
>> 110 or 220, there you go. So I'm just gonna take this code block here, this is the contents of our function up top. And I'm gonna replace this one line with this. So now I'm saying, I think I left this here just so we could hover over the type, but we can do that just fine with it here.

[00:03:44] So we can say if the car's charging voltage is not equal to undefined. Or we could write this as, if it's equal to a number, you could do either. Then we're going to add to this string, what's the charging voltage? And we'll do console log string. But charging voltage is not there, and we need to account for the fact that not all cars are electric.

[00:04:18] Charging voltage doesn't make sense on a gasoline car, so we need this to be an optional property. And what we can do is add it here, and we're gonna use It actually copilot is super annoying today we can use this question mark to indicate charge charging voltage like might be there might not be there.

[00:04:41] And if we hover over that we can see that if you if you believe this pipe. In the tool tip where it says number pipe undefined, if you think of that as, or we use double pipe and logic, logical Boolean operators here. There's a potential that it's not there.

[00:05:02] And the fact that we're checking on it here, check this out number or undefined, but once we make it past this it's just number. Once we make it past this check, TypeScript knows that we've sort of eliminated the possibility that it's undefined. And that lets us treat this as a number.

[00:05:25] We'll learn more about this later. But what we're seeing here is a type guard, which is sort of a condition that has type implications, right? The condition is we're using type of. That's gonna work in regular JavaScript. But TypeScript knows that this has special meaning that pertains to the type of charge voltage.

[00:05:48] That's what makes it a type guard. And then we see an effect that is called narrowing, which means an increased specificity of type within this code branch. We'll add braces here to make it obvious fall within these braces. Charge voltage is a number. So we've made it more specific, why do I say it's more specific?

[00:06:11] If we think about our analogy of sets, charge voltage, the set up here the allowed values of what all possible numbers that you can create in JavaScript and also undefined. And in here, it's more specific because we've eliminated undefined. It's a smaller set. It's a subset of the original.

[00:06:35] So we've narrowed it down. Only slightly, but in a very important way that lets us use this as a defined property. So we can see here our original function will work. And if we pass in a charge voltage that's fine too. That's an optional property. And by the way, the same thing works on function arguments here.

[00:07:04] This is gonna blow up the function here. It's gonna be very unhappy, but I can do this. And now we're gonna be told Whoa, we don't even know if cars here like you can't just reach in there for a dot make that's not safe. Up here we'd have to say like, if car or if yeah if not car.

[00:07:26] No card to print, exit. All right, and now down here we could say, all right, well, we know the car is here. We know the function exited in the case where it was undefined. This is another type card, right? TypeScript knows this isn't just any old Boolean, any old condition.

[00:07:44] This is something that has meaning. as it pertains to the type of car and it knows that we return. And so it knows well if you're down here there's no question mark here anymore. We've narrowed. I'm gonna undo this cuz I think examples down below. Depend on this actually accepting a car.

[00:08:08] All right, great. So TypeScript does this thing called excess property checking around objects. And what we've done here is we've added a color field. To this, this car object, and we're saying it's red and TypeScript getting all angry at us. It's saying object literal may only specify known properties and color does not exist in type.

[00:08:36] And then it lists the type that we've actually defined for the argument to the print car function, so let's saying we can only list known properties. And you might wonder, why would TypeScript prevent us from passing this in? We're giving it everything at once make model and year.

[00:08:54] There's no charging voltage here, but we don't need to provide that it's optional. Why would it object to us passing this in? And it has to do with. There being no point to doing this. Meaning, this is an object literal. We have a field here, that is not going to be used inside the printCar function because the printCar is typed like there's no color here.

[00:09:20] So within the printCar function, you're not gonna be able to reach for color. Okay, so it's fairly pointless for us to do this. It's an excess property. Now, if we wanted to, we could take this and now pass it in. And TypeScript is not going to object to this because now there's a variable here.

[00:09:44] And we can access color like there is some scope where we can access the color property and it's no longer just this sort of this thing that's just almost guaranteed to be safely removable. I have a question from chat.
>> Yeah, would this be the same thing as if you use the spread operator and spread it into the function as well?

[00:10:12] It wouldn't check for the extra property if you spread an object into there.
>> So that's a little bit different. Let me address that with an example here about the spread operator. So, let's create a new function here, and I'm going to make a little section here in the notes, and we'll call this, I see what you're saying with the spread operator.

[00:10:38]
>> Yeah, if you spread my arms into there, it wouldn't or just the object.
>> Well, you'd still have to do like this, right? The point here, I don't think the spread operator, let's try the worst the worst scenario.
>> It might be irrelevant, to be honest, but.

[00:10:56]
>> It might be irrelevant, I'm curious now. Yeah, so here you go. We've defeated TypeScript's helpfulness here. We've we've created a value here and we've spread it into an outer object. And yes, like TypeScript no longer warns us about this. Now, it's still the same problem. There is nowhere because this is an object literal, it's not a variable.

[00:11:19] So we have nowhere like in this scope out here. We can access color, we can't access it from within print car. So this is like you're defeating the helpfulness here, but you're like this is a valid point. This does not make the error occur, but it's also like when you just take an object like this and spread it in It's kind of odd here.

[00:11:43] Now, of course, you could do this. I'm changing my opinion here slightly. Let's do this. So you need much more sophisticated analysis here. To figure out within a spread statement here, what's usable and what's not usable, right? We're not creating an object literal in the simple sense anymore.

[00:12:08] We're assembling an object like behind the scenes, you can almost think of this as like object assigned and you're building up your object here. Maybe one day, TypeScript will figure this out, but there's a lot more dynamic behavior here. You could even, if you had a function that returned an object, you could do something like that, right?

[00:12:28] And take its return value and spread it. And so it's not as simple of an analysis as just looking at a property and seeing. All right, this field you should get rid of.