TypeScript 3 Fundamentals, v2 Address Book Solution
This course has been updated! We now recommend you take the TypeScript Fundamentals, v3 course.
Transcript from the "Address Book Solution" Lesson
>> Mike North: Let's start by renaming this file.
>> Mike North: I'm renaming it to ts, I'm going to go to my tsconfig, and add allow implicit, sorry, noImplicitAny, setting this to false. So this option disallows ImplicitAnys and I wish to allow them. It's kind of a double negative. So I'll save that and go back to our file.
[00:00:34] Now we actually are doing kinda okay here. There are obviously a lot of ImplicitAnys, but we haven't run into too many problems here. Let's see, contacts, it's an array of anys. This is a clue around that array of anys versus array of nevers, we're in a loose mode now, so it looks like we're actually done.
[00:01:04] Let's run our test again.
>> Mike North: Good, so they've finished running. All right, and this is where we make a commit, open up a poll request, and regard this as getting our foothold into the Typescript world. Anyone who remember step two?
>> Mike North: Forbid ImplicitAnys, so making our anys explicit.
[00:01:31] In this we're gonna have quite a bit of work.
>> Mike North: Now we can see in our gutter here TypeScript's telling us there are many places where we need to address things. So I'd like to start with formatDate, so we have to find a type for date. Does anyone have an idea of what this might be?
>> Speaker 2: Date.
>> Mike North: Date, this is a clue, right? ToISOString,
>> Mike North: Okay, so that's happy. What about getFullName?
>> Mike North: Pardon?
>> Speaker 2: String.
>> Mike North: Let's try it. So I'm getting errors that Property's firstName, middleName, and lastName are not on string. Got to be an object, right, with properties on it.
>> Mike North: So I think it's gonna be firstName, middleName,
>> Mike North: Save. Okay, so now this looks to be happy. So this ends up being kind of an array of strings that we've filter for anything missing. This could be all optional, this filtering gives me clue that there's something falsy there that were trying to eliminate.
[00:03:05] We'll come back if it starts to serve to bug us. All right, now this one looks a little gnarly, so I actually would choose to kind of wait until the end. The problem we're running into here if we look at contact we're accessing all sorts of stuff off of it.
[00:03:26] So this is using a fair amount of whatever structure, this using a lot of it. And there's our date, formatDate we're passing in, but we should probably be passing in deep if that's it should still be fine,dates define somewhere. No, it's coming from up here, we're good. All right, let's look at AddressBook, so contacts.
[00:03:57] So obviously, this needs to be type the same as the array up here, right? All this method is like a convenience that lets us operate on the underlying array. Here we're filtering through and there's c, so c has firstName and lastName. So this looks a lot like the data structure we were working with in the function below, the name parts.
[00:04:22] This is a point where I'd say, it looks like we're using this in several places. I probably want to create an interface for this. So I will go ahead and do that. There it is, so we'll just call it Person, and up at the top,
>> Mike North: And so we would say that contacts should probably in array of Persons.
[00:04:55] And this will take in a single person.
>> Mike North: Filter has a property on it, it's firstName and lastName. So again, I haven't identified that this is necessarily, it could be a Person. I mean, it's checking to see if they're undefined. It fits for now, we haven't found a reason for it to not fit.
[00:05:20] I'd wanna make a note here that I should probably come back, I may be over-constraining this. If it's just some properties of a Person, and now that I'm thinking about it it probably is, you wouldn't want to require that it be a full thing.
>> Mike North: Those undefined checks make me want to make firstName and lastName optional.
>> Mike North: Okay, so this piece of code is happy. Actually, our whole AddressBook seems to be happy. Now we're in the gnarly area. And just for convenience and being able to not scroll all over the place, I wanna move this down so it's close by. All right, we have a salutation, salutation falling back to an empty string.
[00:06:13] That's a clue that a string would probably work here.
>> Mike North: And the fact that I need a fallback at all suggests it could be falsy. I guess maybe it could be an empty string, but this should be okay. Okay, then we've got phones and addresses. Anyone have an idea for this?
[00:06:38] Does this suggest a particular shape of this value to anyone?
>> Speaker 3: Op code.
>> Mike North: It's an object, Object.keys.
>> Mike North: So something like that, right? That's what Object.keys wants, it wants an object. Let's see, this type error,
>> Mike North: It looks like I am reaching into that object and passing in pHName.
[00:07:22] This error messages is pretty good one to follow. What does it suggest we do next?
>> Mike North: What are we missing?
>> Speaker 4: And phName to your phones property.
>> Mike North: PhName is just a string.
>> Speaker 4: Keys.
>> Mike North: I'm looking at this it has no index signature. Let's add an index signature, cuz we're taking an arbitrary string.
[00:07:47] We only know what the string is at runtime, right? We're just iterating over all of the keys, passing that key in. This is what dictionary access looks like. Where we can pass in a key and we get a value back. So this is where we need.
>> Mike North: Something like that, and I'm gonna bet addresses is similar.
[00:08:11] We could look at it, but AddrName, let's just prove it to ourselves. Here it is, reach in to the addresses object, pass in the key, get the value out, right? Telltale sign of a dictionary or an associate of array, passing key at value.
>> Mike North: So now we need to figure out what these things are,
>> Mike North: So we've got on address, houseNumber, street, city, country, state, postalCode. I'm gonna just make some reasonable guesses for these based on what I think the type should be.
>> Mike North: HouseNumber, number, street, string, city,
>> Mike North: Is a string, state is a string, postalCode seems like a number could be a string, it doesn't really matter.
[00:09:19] These are all just sort of strings or interpolated things.
>> Mike North: Okay, and contact has an email property.
>> Mike North: And all of my red in my side bar has gone away here. Just so I can show you one more place where this information pops up in VS Code, there's this Problems tab.
[00:09:50] And cuz I've been opening and closing a lot of files, some of these are not related to our example here. But this gives you sort of little sticking points within your code, places where the compiler is finding errors. So there we go, and this would be another commit.
[00:10:12] Because we've gotta run our test, we can't forget that. I don't expect any problems, cuz I think we were just adding type information. There is a problem.
>> Speaker 5: I think phones has the wrong type for the value.
>> Mike North: Thank you, phones has the wrong type for the value.
[00:10:30] Let's look at this, look in the fixture data postalCode should be a number. So we're getting a type error in the tests themselves. Let's go address that, and your phones, there's nothing here. Did you suggest it should be a number?
>> Mike North: It looks anything stringifiable here, I'm willing to accept number if the tests are happy.
>> Mike North: All right, let's see what else we got to do. Type string is not assignable to number, it's a string,
>> Mike North: There we go, so now we know our back and our normal state, assuming our test coverage is good. You see how much we are leaning on the test coverage to make sure we haven't substantially alter the code in a way that will cause problems.
[00:11:36] And the last phase here is going to be going back to our tsconfig, enabling strict mode, strict: true, strictFunctionTypes: true, strictNullChecks: true and not that it matters cuz we're not using BindCallApply. But for completeness we'll set up that as well, and luckily, I don't see any errors here.
[00:12:04] So it turns out our third step was kind of a no-op where nothing new popped up. We actually got to the finish line with only forbidding implicit entries. But it would be totally possible for new things to pop-up that were fine in the loose mode, and sort of only became true violations once we turn those compiler flags on.
>> Speaker 6: So if I accidentally added commas as I was writing my interface. It seems like those are fine to do.
>> Mike North: They are, commas are find between key-value pairs and interfaces. The reason I prefer to use semicolons is, it helps me visually identify the difference between and an object type and object value.
[00:12:49] As you point out, both are fine. I use prettier to automatically format things every time I save, and it's gonna replace commas with semicolons.