This course has been updated! We now recommend you take the TypeScript Fundamentals, v3 course.
Transcript from the "Challenge 2: Solution" Lesson
>> Mike North: So we're going to go through the solution for this second exercise and what you'll get into the habit of doing as we start working with a type script editing environment. You'll start to learn to look at these problems that pop up and I'm using visual studio code, it's what a lot of people use to work with Type Script.
[00:00:20] I'm sure you can set other editors up to do a similar thing. But what it's complaining about is all of these implecent any's. So I'm hovering over this register function and this tool keeps popping up telling me that email and password, there's no way, since I'm not really doing anything with this data other than sort of placing it into an object down here on line 14 and pushing it then to an array.
[00:00:45] There's no way for me to know what type those are, right? There's no tail tale sign that like those values are of any particular type. So all I can do in order to make sense of the situation is say I wanna give it the most flexible type that exists and that is any.
[00:01:05] In our Type Script configuration and we will learn about this file bit by bit.
>> Mike North: So this tsconfigjson this setting here is what's leading it to complain about our complicit anys. So we will learn about different things you can do in this compiler options object bit by bit.
[00:01:29] But that is where this is coming from. So let's begin. So we're gonna define what it means to be a user. And for that, we're going to build an interface called user, all right. It's complaining about an empty interface. This doesn't do us any good to define an interface that has no properties.
[00:01:51] That would be the same as basically an interface that looks like an object literal, right? But we know here we've got an email. That's a string. And a password that's a string. And now we can actually take this users object here and we will talk about arrays a little bit later on.
[00:02:18] Now you didn't have to do this but you could do something like this
>> Mike North: So now we know that users is an array of objects that conform to that structure. They could have additional properties, they don't necessarily have to. So down here, I'm gonna say I'm taking in an email, which is a string and a password, which is a string.
[00:02:44] And I am returning an object that looks like this. Now it says it's returning an object that has an email and a password here. That is, that conforms to the same structure as a user. But you note that I didn't have to explicitly define the return type here.
[00:03:00] Transcripts pretty good at figuring out what you're returning. And, in this case I just want it to refer to it by the name, user. It's got a semantic name for it now. That's the only reason I had to add that there. Everything would've been happy, except me the developer.
[00:03:28] So activate new user and I've got user to approve. So, if I were to say this user to approve is type user, and the approver is type user. We're gonna get a little bit of a problem here. So is active is not on user Admin since is not on type user.
[00:03:46] So what we can do here is, we can do something like this. There are many approaches you could've taken.
>> Mike North: And then deliberately, I'm trying to avoid things that we haven't talked about yet.
>> Mike North: So there's a confirmed user and then we can have an admin that goes one step farther.
[00:04:21] Oops one click poured brook for me.
>> Mike North: And adminSince is the last thing that's missing here. And what should I put for the type here?
>> Student: Date.
>> Mike North: So you can use any constructor as the type in addition to those primitive types and interfaces.
>> Mike North: And here the approver must be an admin, so now this is great, I've got some nice constraints that describe exactly what I'm looking for here.
[00:04:55] Registering creates a new user, activating a new user. Actually this is gonna take in a regular user. But it's gonna return a ConfirmedUser. And what we can do here to make, so what it's complaining about is essentially we are mutating in place. Think about that, I mean we are mutating in place this user.
[00:05:18] We're gonna do that anyway, but we have to define it. We have to kind of get a new reference to it with a type as we transition it into this confirmed user. So we could do something like this.
>> Mike North: And now TypeScript will be happy. So it's an extra line of code, but it does serve the purpose of helping us understand we're being very deliberate about stepping over this line.
[00:05:51] We could even do something like this.
>> Mike North: And avoid the one line.
>> Mike North: Well, no, we're still gonna have to do it that way. Anyway, better to have it be explicit. But in some cases, you can do it in two steps. Doing it in one step. Sorry. All right we're returning a confirmed user, promoting to admin.
[00:06:24] So we'll say in order for a user to be promoted to admin it has to be confirmed and only and admin user can do the confirming. And so again here we're gonna say let newadmin = user as Admin.
>> Mike North: Something like that. Now we might be going overboard and being so explicit about defining all of these different states.
[00:07:01] But the end result here is if we were to say, I've got a new user down here.
>> Mike North: E-mail.
>> Mike North: So that's our user.
>> Mike North: And we're to say.
>> Mike North: Sorry AM.
>> Mike North: Lets make ourselves an admin too.
>> Mike North: Just became an admin. So promoteToAdmin and we're gonna pass in,
>> Mike North: Pass in our admin. And passing that user, it's basically in the complaint and say, this is an unconfirmed user. So this kind of thing like because we've defined these types, now imagine how this might work, like effectively we got a little bit of state machine or the makings of it now where, you know, we take in an object of one type and we add a field, then it becomes another type.
[00:08:23] And as we have references to these things, we're catching something now where this was potentially a not confirmed user, and this would have been something where we'd depend on dynamic validation in order to catch it, and we have to be lucky that we have the right test in place to nail this.
[00:08:40] But now, at build time, we get some feedback saying hey, this user wasn't confirmed yet. You can even go up here. We'll learn about this a little more later. We can say, this isn't just a boolean. It is what's called a literal type. So the value of this property is true.
[00:09:01] And what that means is if I go down here and I say, false, even if this guy is confirmed. Sorry. Confirm user, let's see. [SOUND] Interesting, is active site. Sorry, I have to do it down here as well.
>> Mike North: So now down here it's complaining to me that like, that flag there, [LAUGH] it's either absent or it's true.
[00:10:06] It's really cool to do this, really cool to be able to get this so early and so quickly. Last thing I wanna show you is we've done this in sort of a silly way. There's a lot of redundancy up here, you can treat interfaces in a similar way that you would treat classes.
[00:10:21] We'll dive into this a little bit more later, but I'm just gonna commit this as the solution.
>> Mike North: So with say that this confirmed user has everything user has except that also has that active property on and that's got to be true. And admin has all of that and adds admin since.
[00:11:07] Here, we'll get some feedback. For example, if when it use a registers, or like we say here is, we'll just change the surround a little bit. Because we define this as a user now. We don't need that annotation at the end, it's basically gonna infer that this is the value you're returning.
[00:11:27] And it's not simply this structure here, it has a name, you've given it one. That's all I did by moving that down. But if I were to do something like this.
>> Mike North: I'm not allowed to do this. Now and this ensures that this function here, where I'm registering or whatever I'm doing here with this user, it stays generic.
[00:11:51] It stays in a state where I'm working with things that work across all users, regardless of whether they're confirmed or whether they're an admin. This would be tough to do, tough to get this kind of compile time feedback. With lose objects that don't have that rigidity of structure that we have to define up front.
[00:12:10] All right so, yes question.
>> Student: Yeah, around line 56 you have the new user as admin right there. So, new admin, there's no way you can ask type script what type is this variable out of here, right? Cuz it doesn't really have a type. It just has properties.
>> Mike North: So yes, that's right. That's where we're talking about structural typing instead of nominal type. So you would say, what's your structure.
>> Student: Yeah.
>> Mike North: And it would say, I have these properties, and the properties can have the following types. And on top of that, there's no way to write that in code because you have to remember this is almost like linting plus.
>> Student: Right.
>> Mike North: So there's no run time reflection API or anything that would say are you an instance of this interface?
>> Student: So then on line 56 too, since you haven't defined adminSince, if you returned newAdmin but promote expecting admin to return, would it err because you'd actually have it in front of that property?
>> Mike North: Can you try to ask that a different way?
>> Student: Definitely, so right now, newAdmin on line 56, doesn't have all the properties, this of admin interface.
>> Mike North: Correct.
>> Student: It doesn't have admin sets.
>> Mike North: Correct.
>> Student: So if you try to return it online 58 without 57 would you get some sort of type error?
>> Mike North: The value of that property would be undefined. In the same way that if I were to do something like this
>> Mike North: All values of this property are undefined.
>> Student: Umm, got it, so it's adding the property, just giving it no value.
>> Mike North: Yes.
>> Student: Cool.
>> Mike North: It has the shape, and we can mutate values, right, but undefined is still a thing that can happen there.
[00:14:01] Now what we could have done, there would have been a way to do this in one shot, but I would have looked something like, we don't know these operators yet. User.
>> Mike North: So that also makes typescript happy. This is basically saying, take everything on user, unpack it into an object in addition to that add this property called adminSince.
[00:14:30] And let's regard that whole thing as admin. And in fact I don't even need this, simply because all that did for me was give this structure a name. We'll learn about that later, I just want you to know that this extra line of code, which is rightly potentially bugging some people like why did we have to have this extra line.
[00:14:48] It's just x=y. We will get rid of it but we have to learn more about operators and enhanced object literals and things like that in order to get there. But a hopefully you see the benefit of types here, where we have so much more structure and compile time assurance to run this code than we ever could with java script.
[00:15:09] I've changed the format of the branches a little bit so there's a per excercise completion branch. I have to catch up and do the next exercise, it will be no problem, but it's gonna follow this form femasters/ and then the exercise number slash complete. So if you wanna jump in and out of this course later on and you know, just try one exercise, you can check out the begin branch and that will get you queued up for the right exercise and then the complete.
[00:16:27] Don't panic if you see some code and for some reason you're testing it out on your machine and you see some errors, we will clarify all of those errors and get aligned with type script in a moment.