What do you want to learn?
Leverged
jhuang@tampa.cgsinc.com
Skip to main content
Pluralsight uses cookies.Learn more about your privacy
Play by Play: Angular with Typescript with John Papa and Christopher Martin
by Christopher Martin and John Papa
Learn Angular concepts in Typescript while seeing how experts problem-solve. In this course, developer Chris Martin and John Papa convert an Angular application from ECMAScript 5 to TypeScript, teaching you important concepts and tooling as they go.
Start CourseBookmarkAdd to Channel
Table of contents
Description
Transcript
Exercise files
Discussion
Recommended
Introduction
Introduction
Welcome to this Play by Play with Pluralsight. Play by Play is a series where we sit down with an expert to work on a solution in real time. It is unscripted and unrehearsed. In this course, Chris Martin, a master in Knowit in JavaScript developer, walks through converting an angular application written in ECMAScript five, to TypeScript from top to bottom. We challenge Chris with setting up TypeScript tooling and coding Angular One concepts, such as modules, services, controllers, and directives, all with TypeScript. We learn as he explores the benefits of migrating from JavaScript to TypeScript using classes, interfaces, and static type checking to benefit from better tooling and detecting and fixing issues early. Chris helps us explore TypeScript editor support along with IntelliSense, autocomplete, and refactoring features, an IntelliJ IDE, and VisualStudio code. Then we adjust Chris' gold file for building and linting TypeScript files, and along the way, we debate different topics, such as the merits of using functions versus TypeScript classes for various angular concepts. Please join us on this journey through buliding an Angular One web application with TypeScript. Learning from Chris, we hope you enjoy it.
Configuring the Environment and Transpiling to TypeScript
Project Overview and Tour
Hi, my name's John Papa, and I'm with Pluralsight. Today I've got my good friend Chris with me. Hi John, I'm Chris. What do you do for a living? I write JavaScript for a living. That's a good thing (laughs), because we're here to talk about JavaScript today, aren't we? So, today Chris and I've been talking about building this Angular app with JavaScript and we had an idea, why don't we convert it over to TypeScript and see how hard it is to take an Angular 1 app written in ES5 or ES two thousand whatever the heck that'd be, actually isn't a two thousand anything, they renamed ES recently, and convert that over to TypeScript and see kind of what happens with the editor and the code. Definitely, yup. Let's dive in. I'll show you the app as it runs. I've got this reading buddies app that works with the Goodreads API. That's a public API? It's a public API. It's free, you can sign up as a developer to get a developer key, I've done that, and I have a bunch of friends that I follow, and am curious about what books they've read, and they rate them and these numbers up here, four, five, they've rated them, these are the recent book reads that they've done. Like a scale of one to five? That's right. And I can aggregate them and view them all on one page. Hey, The Martian! That's a good one. That's right, that was a good movie. So I've got a simple Angular app. Two views, two views in my routes. There's a configuration page that tells me which Google users I want to follow, and I can add new ones. Like a Google+ account, kind of thing? Yeah, essentially. And if I add one there, it'll show up, and Felicia shows twice here at the bottom. Cool. Are you friends with Wil Wheaton? Uh, no, no. (laughing) Okay. But a very entertaining guy. He is. So that's basically the app. On the Angular side, if we want to go into that? Yeah, let's take a look. And I got to ask you first, so we all use different editors and IDEs, I noticed you're using IntelliJ IDEA, what's that? I'm not familiar with that as much. Yes, it's the IntelliJ suite. This is the one that is usually used for Java programming. It's full featured, everything, you get everything. Is it similar to WebStorm? Or is it like the same tool, or? How's that? It's very similar. It uses the same WebStorm plugins. Okay. But they have a whole suite of IDEs... Okay, yeah, that's JetBrains, gotcha. With JetBrains. So IntelliJ's like the big IDE, that looks, kind of to me, the way I'm reading this, it looks kind of like Visual Studio is to like .NET programmers, I guess IntelliJ must be for like Java programmers? Yes, yeah. Does like PHP and other stuff too? Right, they have PhpStorm, I think, and a bunch of other web app editors that are tailored just for that application style. Cool. I'm just interested in that because it seems neat that TypeScript isn't just for Microsoft people, since that's where it came from, it looks like, I mean, you're doing IntelliJ, take it you've done some Java before too, so this is your editor of choice. Does it support TypeScript? It does. Oh, awesome. I gave it a try. I'm new to TypeScript, but I've done some dabbling with it. Alright. So hopefully it's not a train wreck today. We'll see how it works, it'll be great. We like train wrecks too. Awesome. Alright, so let's see it look at the code. So the code, everything here is under client, source app. And let me maximize this. So our project is organized in these folders. Okay, so we've got a client at the root, we've got a server at the root. Is that a Node server? It is. It's an express.static server. If it's okay with you, today let's just convert the client app, and we'll leave the Node there, because I think we've got enough on our plate to do, right? Definitely, sounds good. This is the index.html entry point, it's loading a vendor bundle, my application bundle. So those bundles don't exist yet? They do not. They're bundled via a Gulp process. Oh cool, I like Gulp. Which is running here. Alright, so you've got something running in the background. Is that like a watcher for TypeScript? No, we don't have any TypeScript in here today. Not yet, okay. It's just watching on JavaScript changes, and will trigger browser sync. Rebundling and Yes. Gotcha, so that's what's loading your application? That's right. Awesome. Let's take a look at some of the JavaScript that you've got in the files, maybe one of the controllers. Sure. The main entry point here is this app module. And this is using I guess the pattern in your style guide. So ngSanitize, you must have some HTML content we're going to convert, rerouter make sense ngStorage, is that local storage? Yes, those Goodread user IDs I store in the browser with ngStorage, with localStorage. Okay. We've got some configuration functions. Angular, where we're initializing-- Their debug info on, awesome. Yup, and our router. And we got the router states, then we got some more storage settings. That's just to let up how you're going to do it. If this is the first time we're loading the app, we're going to set some default configures. Sure. And then we've got our admin controller. Pretty simple, couple of methods. Yes. Nothing I can't see too hard yet, to convert. We've got another controller, the home, which is even simpler. That is (laughs). We've got the API service, this is what is communicating with Annex API. Which is then proxying to the Goodreads public API. Okay. So it's a shared service that if we were reading books on more than one page, this would be the place it would get its data from. Correct. Alright. And then the directive has most of the goodness in it. Now, is that directive wrapping one book in a list, or is that the entire list of books? It's wrapping, if I can go back to, it's wrapping this entire section. So you feed it the Goodreads user ID and it will fetch the last five books. Gotcha. So Tom Merritt and all of his books are one directive instance, and then Veronica's the second, and those are probably in some kind of a ngRepeat somewhere? Yes. Okay, where's that ngRepeat located? It is in the home. First we're repeating over all of the readers, Okay. Here. The readers are the people? The people, yup, the user IDs. And then the latest book reviews. And that's your individual directive? That's the directive. And you pass the reader in through scope, and that's how he's binding to everybody. Yes. And then in here, we're ngRepeating through the reviews, the five book reviews. Gotcha. And that's how you're getting your little ratings up there too. Right. Displaying a link to the review, their image URL. I think it's funny that if the book is less than three, it's a danger. (laugh) "It's dangerous to read this book!" Right. That's hooking into the Bootstrap style. Oh, gotcha, okay. Just showing red. (laughs) Nice. Well cool. It looks like a relatively straightforward app. We've got a little of everything too, right? We've got a service, we've got a controller or two, we've got a directive, we've got modules, a config, and we've got routes. So cool.
Initial Conversion and Transpiling to TypeScript
Where would you like to start with this? Well, um-- I hear it's relatively easy to get started with TypeScript. Yes it is. By just we're renaming the files from js to ts. That should just work, shouldn't it? I'm hoping. Okay. So why don't we take a look at that? If I go into here, and Reveal in Finder. Yeah, because if we just take the JavaScript files and rename it TS files, JavaScript is TypeScript, so it should just be valid TypeScript and everything should be fine. I'm going to rename these six and replace with TypeScript. That's neat. That's a command you can use? That's just built into Mac Finder. You can multi-select your files. And then what command did you hit? Just Rename File, right-click? Or, two finger click (laughs)? Yes, just right-click and Rename 6 Items. Awesome. So they are TypeScript files now, my Gulp process is probably going to start freaking out. Yeah, probably. It's like "What did you do with me?" (laughs) So there's the TypeScript compiler, Okay. Tsc? That's a command line utility that we can run. Is that the same one as the, so when I use that I use npm install typescript and the TypeScript package that comes down off of npm, that one has a command called tsc built into it. Or are you using the one called tsc? because there's two different ones. I was using the one called tsc. Okay. And I install it via npm install global. Okay. So that means if we do it global it means everything in that machine's going to use that version of TypeScript. And if we do it locally, we could have different things using different versions? Yes. For now let's just go global, because it's going to be easier. Right. So if I run tsc, let's see what options there are. So we can do --help. Yup. I want to point it to a directory. So -p directory. Yeah, p stands for project or directory. So you can do -p and then the name of the folder. So tsc -p, and my source is under client, let's just point it to client. Okay, everything under client? Yup. Alright, so it's looking for a file called tsconfig.json. So what that means is that TypeScript has a theoretical project root and the project root, it looks for a configuration for TypeScript. So if you just say "Hey, look, "all my configuration for compiling TypeScript "is located in this folder," it'll look for a file called tsconfig.json by default, it'll look for all those settings, which we can talk about those settings, and then it'll use those to compile. So maybe a good place to start would be to start setting those settings. Yes. Let's look for an example tsconfig. That would be a good idea. There's a couple out there, you can get one off my GitHub site, you can get one off of you can just Google tsconfig.json as well. So the TypeScript Wiki. Atom-typescript, TypeScript Deep Dive, there's a couple up there. What if, let's see. There's this guy named John Papa. Yeah, let's go into yours. (laughs) I'll find out my repo's name. You'd think I'd actually know the names of my repos. That's not it. TypeScripts. It's called hottowel-angular-typescript. Yeah, that guy. Should be in the source folder, the src folder. And into client. There we go. Wow, there's not much there. No, there isn't. And frankly, you don't need this file. What you could do instead is you could set all these flags individually on tsc. So you could type tsc -noImplicitAny, tsc -removeComments, you could put all these things in one long list. But that's kind of a pain, and what if you forget to type one or? By having a config, this is going to make us a lot easier to deal with this. So let's create one of those. And where you put it's important, so you notice you're putting it in the client folder. That's good because that means that that's the root of your TypeScript project, everything under client. Which is good because we want it to anything in node_modules or bower_components, and all that's back at the root. And I also have a test folder in there, so that it could potentially drive the configuration for-- For your unit test. Which is great, because you want those to share it. Right. So I'll copy that in there. We've got noImplicitAny: true, so this is the double negative. Yes, so noImplicitAny means that in TypeScript there's a variant-based anything data type called Any, and if you don't want people to implicitly imply any (laughs), then you have to turn that on, which is on. If you want to be more relaxed, you turn that off. So that would be false if you want to, let's take it easy since we're converting. Yeah. Let's ease into this. To be clear, if we left it on true, every time we'd have a type, we'd have to define it. It would throw an error or a warning. Yes. So let's turn it off for now, we can try to turn it on later if you want. Removing comments, that's kind of up to you, if you want to leave 'em in or not, I usually remove them in the transpiled code. Now, I am using ngInject comment with a Gulp plugin that will scan those and automatically add the inject information. So you want to keep the comments in this case. That was one of my fears, is if I removed comments there would it mess that up at all? It would, because that's a comment flag, that's the ng-annotate plugin I assume you're using with Gulp, so yeah, that would remove it. What you could do, is you could remove the comments then have something else add them later. So the ng-annotate plugin, even if it doesn't see the comments, it'll still do the annotations. But there are some places still where it can't figure out where to annotate and it needs that comment. So to be safe again, let's not remove comments. Okay. PreserveConstEnums. That's fine. And we are targeting-- ES5, yes. We'll go back to that, every browser supports it so we're good. I'm going to disable this, sourceMaps, for now. That means we're not going to be able to debug the TypeScript in the browser. Right. I am doing sourceMaps with my JavaScript bundler. So anyway, we can talk about more about that. So you're bundler is going to handle it for you. Yes, right. But it is nice to have the sourceMaps trace all the way back to your TypeScript files. It is. So it just depends, it's not that you don't want them, you don't want this guy to do it, and you're going to handle it with Gulp? Right. And what is listFiles? I'd have to look that one up. It's not like I was using it in my own repo, was I now? (laughs) So listFies tsconfig.json. I had forgotten what that one stood for. Let's see. If I come up to its setting, it says here that listFiles, not remembering that. Let me look for that and we'll keep going. Are there any other settings that you want to set up? Not that I know of. Let's try it. Okay. So now it should be able to find the tsconfig. Now it's not finding things like Angular, like it doesn't know what Angular is. Let's go look in one of those files and see what it's complaining about. So we'll go under, the simplest app module, ts.
Adding Dependencies to Namespace
So it can't figure out what Angular is. Well, that makes sense right? because that's a variable and it's like Where the heck is that? So when TypeScript starts with your project, it wants to know, Okay, you've got this thing called Angular now, it wants to know what type that is, what that thing is, and we haven't told it. So TypeScript has these things called type definition files. They're d.ts files. So we have to go pull those in to the TypeScript project. And there's a couple ways we can do that, we can manually type them from scratch if we are masochists and we want to type forever. We can go download them off the DefinitelyTyped GitHub page, which is where most of them are stored. There's another tool called tsd, which is command-lined and that will help us install them automatically. Let's check out that GitHub page. DefinitelyTyped. Yeah, that first one. So on there, and there should be an Angular folder somewhere, it's a massively long list of-- Let me go to their main site. Yeah. And so what you do is you reference that file name, like jquery.d.ts. So we can search for one there. Would you like to download it directly? Or do you want to use tsd to install this? Let's use tsd. Okay. That's the TypeScript definition manager. And we can install that globally here, with the same tsc command. So let's go down there, npm install tsd -g. Hopefully npm cooperates with us. While that's installing, we will install Angular. Angular's typing files. I assume the syntax, let's see, read me. For installing? Yeah, I always have to look these up. Tsd install. The thing, and you can list multiple if you want. Right. It's just like npm, you say save and it'll save it to a local file for you. Gotcha. So let's try installing it. Tsd install angular save, because we want to save this. Alright. Now it should've saved those into a tsd.json file in your root, wherever you're actually located. Let's see if it created that. Did it create a tsd.json file? If it didn't it might be because we have to do a tsd in it. It did, okay good. Notice it got jQuery and Angular, that's because Angular actually depends upon jQuery. Well, it doesn't have to, but it can. So now we've got both of those in there. There's no harm having the jQuery-- Not at all. Thing around? And the path is important, so that path is typings, that's where it's going to put those type files. Let's go look in your typings folder. And you can see jQuery and Angular, and if you'll open up that dts real quick, on one of those. Yup, so they're pointing at both. This is the main dts file, I guess, that as you install it will add additional references. Right, these are reference points. Let's open up the Angular d.ts file, just briefly, and we'll never go back (laughs). These are all like, interfaces and ambient modules. This gives basically types, it's a typings file. This way the tool, or our code, now knows more about it. If we look back at the tsd.d.ts, That's a mouthful. Yeah, it is, isn't it? That will reference both of the things we're using. Any third party component we have, that you're using in wrap, you're going to want to reference through here. Are we using any others besides Angular? I'm using that Angular storage. Oh, ngStorage, yes. NgStorage. I don't know if... Does it have a DefinitelyTyped, that's the question. So if we go back to this search, so, uh, ngStorage. And there is none? It does not look like it. Angular storage. Nope, nothin'. Okay. So we may not be able to leverage the typings, or we could create our own for that third party library, potentially. Yeah we could do that, that might be the best way to go. I'm sure somebody's got something out there for it. We could type them in by scratch if you know the APIs too. Want to do that? Yeah, sure. Okay. Let's create a ngStorage.d.ts somewhere. Okay. Around the same area, or at the same level as the folder that the dsconfig.json? That would make sense, because if we put it in the typings folder at the root, currently the way tsd works is it overwrites the stuff in that folder. So we don't want to put any of our own stuff in there yet. They were working on a way to not do that, but for now let's create our own typings folder in the client, and this is where we'll put our own custom typings. We'll create a file there called ngStorage.d.ts. Sure, we'll add it to Git. (laughs) Now you're going to have to help me a little bit here, knowing what is in that file. So the API, you're going to want, I assume it's got a namespace like ngStorage? Yes. Let's call it ngStorage. Okay. And when you do this, you're going to want to declare it. So this is actually a typings file, so we're going to be declaring the namespace. So now that we declare that this namespace exists, it's going to have some interfaces in it. So everything's going to be an interface, because we want to be able to use it. Is there like a storage service? Or a storage provider? Or what are the APIs in this? Let's look. Under bower_components we've got ngStorage, let's see how large this is. So we've got a provider. Okay. That looks like it's running through the same type of factory. I've got the code up too, let me kind of look at the code, and you can do some typing. We'll pair program a little. Okay, great. It looks like the API is, there's a service provider, so let's create an interface called IStorageProvider. An interface called? Capital i, capital storage, capital provider. Provider. Cool. And then that's going to extend that's plural, extends, sorry, angular.IServiceProvider. Should be some intel instance hopefully. Do IService, there you go. And then open curlies, end curlies. What we've done there is we're saying, we're creating this thing called an IStorageProvider, that's for ngStorage, and it's extending part of Angular, Angular has this thing called an IServiceProvider. Inside of those curlies now, we'll give it the names of the methods and properties and members it's got. SetKeyPrefix is one of the members, And that's a function and it accepts a prefix parameter. Actually, that'll be setPrefix, open parens, so type it just like a function first. Get rid of the word function, yup. Then pass prefix: String. And then the type of that, so end the parens, that'll be a void. Not avoid, but void (laughs). Cool. Then there's another function called SetSerializer. I'll scroll down, keep lookin'. That's got a parameter called s, and its type is function. Then it's got SetDeserializer, with the same parameters and types, that's the same thing. Then there's a get function. And that passes a key and it's a string. Probably returns Any. Yes. because that's getting something out of storage, it doesn't know what it is. We can store yeah, whatever we want in there. And just like there's a getter, there's a setter. So set takes a key and a value of type Any. That's key value pairs. The value is Any not String, because we don't know what we're passing in. That's right. And that's going to be of type Void. That's the main API, it also looks like there's a couple others here. because it exports local storage in sessions, so want to create an interface called ILocalStorageProvider. And that's going to extend the storage provider interface you just did. Perfect. And then open and close curlies. Then copy and paste that again, because the other one's exactly the same, and it's ISessionStorageProvider. Just like that? Yeah, just like that. Finally, another interface called StorageService. Another interface. It's like an indexer, it looks like. IStorageService? Yes. And inside the curly braces, interface, why is it, oh okay (laughs). Inside the curly braces it's going to be an array, so square brackets. Where it's got a key of type String. And then that whole thing is of type Any. So it's a way to get the storage values out. Gotcha. I remember seeing this in the Angular code, in the Angular TypeScript definition for just having a dynamic set of properties associated with an object. Right, because this can store anything. Let's make sure all of our syntax is good. So we've got storage provider, set prefixes, looks like we're missing a semicolon on that line with the key String. TypeScript's actually lenient, so if you did that it would actually generate it for you with JavaScript. That gives us that type. Now, not to scare you too much because you don't have to do this a lot, this is a not a very popular library, ngStorage, but it's one that's used enough. It's kind of one of those fringe ones, where it's not popular like Angular, but it's popular enough where you want to use it but somebody hasn't gone through the trouble, at least that we could find, of creating the types for it. We don't have to do this, if we didn't do this, this means that we wouldn't get any tooling support, that's all. We want to avoid red squigglies in our code, so we're going to do this because it's small. For example, I would never recommend somebody go do this for something like Angular or jQuery. Oh jeez. You'd be typing forever. Right. So this is just next I show you how a typings file could be generated. Cool, so now we have this file, that means when we start doing our project we could actually reference this d.ts file as well. Along with the typings that we downloaded from DefinitelyTyped. Exactly. Now if there's other libraries that you've referenced, let's go ahead and pull those in too. Like, are you using the Angular router, or the UI router? The UI router. Okay, so we should be able to grab that guy from tsd. UI router. It is there. Exactly. So we'll do tsd install that, with --save. Then, do you have any others in there we need? Like any other Angular dudes? Sanitize. That should just be angular-sanitize. We already got jQuery, it came along with Angular. Yup. That'll be good. It's taking a little while to get that guy. So we'll need Sanitize. If we wanted to do testing, we'd have to do like angular-mocks and other stuff, but why don't we skip those for now? Right, okay. So we'll just wait for him to finish, and then we'll go get the other guy.
Completing the Transpiling to TypeScript from IDE
We got the UI router, now we need to tsd install sanitize. So let's do that. Tsd install angular, if I can spell it, Anagular! (laugh) San-i-tize. And --save. The key is, if you don't save it, it doesn't put it in the tsd.json. The reason we're doing this is we want to have a tsd.json file. Let's go look at that real quick so we understand what's happening. Nope, the tsd.json in the root, yeah. This is a manifest of all the files that you have pulled down off of tsd, the DefinitelyTyped site basically. Like our bower.json, our packaged JSON files. Yes. Right, so we'll check this under source control, so if I grab your code later, I can literally just run tsd install with no other commands, it'll look for the tsd.json and go, Oh, you wanted this, this, this, and this, and it'll pull 'em all down. So just like node_modules or bower_components, I wouldn't necessarily want to check these into our Git project. By these you mean the typings folder. That's why we have two different typings folders right now. We have a typings in the root, which is completely controlled by this tsd.json file. So we will check in the tsd.json, we will not check in the typings, so you may even want to put a get ignore, if you wanted to. Yeah, let me do that really quick. The root typings folder. But we do want to check in the other typings folder. Right, the one that we created for our-- NgStorage. Yes. That should do it. If not, we'll remove it and check them all in (laughs). Yeah, looks like that syntax works. So that'll be him, and then the tsd.json, again, if we just go to the command line, like if I pulled it down, I would just do tsd install, it looks at that file, it would create the typings folder. Where does it create it? It creates it where the path is. If you wanted to move that around, you just change the path there. Then the bundle is the name of the the d.ts file, the definition file, that's the list of all the things. Let's take a look at that again. Cool, that's a list of the four things you had, and then your project, which is wherever the tsconfig.json is, looks in that file, says Where are all the types located? this thing tells it where they're located, and therefore all of our Angular code should be happy once we do that. Our codes knows about this because we put in references? We could. So let's go to the controller for a moment, it's probably still red or green or whatever color it was. My IDE is still complaining about-- It says it doesn't know what Angular is still. Let's mini, minify, minim (laughs), let's close the app folder. Let's un-triangle it on the left. Yeah. Just looking at the folder structure we have, that client folder doesn't have a dts right? Correct. Right, it's got the tsconfig, so the problem we're having now is, even though you have the typings, and we've defined where they are, the tsconfig is the root of the TypeScript project, and that's located in your source folder? Or your client folder? In my client folder. Your client folder. And that's fine, but that means it can't go backwards, it can't go up the chain to figure out, Where are my typings? Couple of things we could do. We could move everything to the root, but then we have a problem because then our node_modules become part of our project, and we don't really want to do that. Right. So I like where we have it. And I don't want to change your structure, because I'm sure you like your structure, why don't we just create a dts file right next to the tsconfig.json? Okay. New file, dts. It'll be called, same as the other one, what was it, tsd.d.ts. TypeScript definition dot definition dot TypeScript. (laugh) Hey, it's a palindrome, kind of. So we can add some of these same like, reference-- We could add the same exact ones, but instead of, which one are we in now? Instead of copying all these. Just point a reference to the other one. Okay. Yeah. So from here, from my client tsd.d.ts (laughs), we're going to point back up a directory. So do it ../typings, Typings. /tsd.d.ts. Cool, so it reconciled it. Now we're also want to get that other one. Right, the ngStorage. Yup. I like copy and paste. (laughing) Yes. If only it would type for me. NgStorage. That's not up, it's actually in the same folder. So we're saying, Hey you know what? Use this one I wrote called ngStorage, which is right next to you, and also go back up to the root, grab the typings that everybody's sharing. Now let's look at your, We go back into that controller? Mmhmm. Is it going to reconcile here? Um (tsks) This TypeScript compiler, I can restart it here. So that's a compiler, it's built into IntelliJ. Right. Okay. It's telling you it doesn't know where tslint is. It looks like it picked it up. Oh, okay. So it just had a-- It just had to refresh. Gotcha. I know like, in VS Code when I do that, sometimes when I move the typing files around, in VS Code I think the command is, F1 or command+shift+p, and I just type in reload window. Because VS Code's actually just a browser, it's built on Electron, so you don't have to close it and open it, you can just say reload window, and it'll like, refresh. Ah, nice. It's like a kickstart (snaps). You know, like a soft boot. Gotcha. I'm not sure if the same thing exists in IntelliJ or WebStorm. It may not. It may just be that it had to recompile. Sometimes like in Visual Stuido if you close the file and go back in, it's happy. Now it knows what Angular is, that's good for us. We probably want to be able to compile our TypeScript to JavaScript. Yes. You want to do that next? Yes. Let's see what the command line does now. Tsc path client? Yup, wherever your source of your tsconfig file is. So it seems to be happy. By the way, I figured out what listFiles was, or remembered, listFiles lists the files. Oh, nice. Meaning if we turn that to true, and then we run the compiler again, it should show us in the terminal what files it created. Tsconfig.json. True. Right. So we run it again. Nice! So we're also demonstrating there is, this tsc command is looking at that configuration, so it's saving us from having to type all that stuff every time, and that proved that when we changed that file it was happy, so if you want to change it back to false, it's up to you. You can leave it either setting you want. When you get a really large project, I only turn that on when I'm debugging, which is why I forgot what it was. I leave it off most of the time, but I'll flip it to true to say, "Hey, is it actually compiling the files I think it is?" because sometimes you think it is, and it's not. Gotcha. This is the command line here, but I also have the IntelliJ TypeScript compiler plugin loaded. Cool. And WebStorm's got the same kind of thing, so it's very similar, this looks just like WebStorm to me. So under Languages & Frameworks, TypeScript, you can enable this here. Nice. And cool, see it says use tsconfig.json or set options manually. Just to give people an idea here, of what we could do, if you did it manually, you would literally have to type out tsc -p, actually you wouldn't do the -p at all, because that's how you don't do it, tsc --listFiles true, --source, Oh, all the arguments. source here -- and it'd be this big long command, and that's just not fun (laughs). Just easier to use the JSON file. It really is, it really is. Then you can check in your settings, because think of it the other way, if you're working on a project that I'm working on with you, if we don't use the same settings, and I pull your code and run the TypeScript compiler with different commands, I might get errors or a different output than you do. Like the removeComments, maybe I've got it on, you've got it off. Mmhmm. And I noticed here, we can change the compiler version too, by giving it a custom directory either through npm installing it locally, to a particular version of the compiler if we wanted, and using that within the IDE, within VS Code, I'm assuming there's a configuration in there-- Yeah, VS Code comes bundled with one as well, but it allows you to override it through a JSON file and a preference. We can take a look at that later, if you'd like, and see how that works. Cool. So that's enabled. While I'm here, we also have tslint. Okay, that's a linter for TypeScript to say, so we've got different levels of things that we're doing, the dts files are to help our editor, well it helps everything, but it helps our editor to make sure that it doesn't have red underlines and knows what we're looking at, and then the tsconfig is be used by the tsc, the compiler, to know how to compile, and tslint is going to look at our code and just tell us if something's wrong or not. Right. You can give it some style settings, just like the noImplicitAnys, you could say, Okay, we want to enforce all of the parameters to have types. Exactly. Or all the functions have, you know. It's just like jslint or jshint, or any of that stuff. There's csslint as well. So lint is just a checker. Would you like to use that? Yes. It integrates well with the IDE, and it has helped me walk me through converting JS code to TypeScript, because right now all we've done to the JavaScript has been renaming the file. Right. So we don't really have TypeScript yet. We do, because JavaScript is TypeScript, but it's going to help us as we go through and type things, so it'll tell us mistakes as we're doing it as opposed to having to run the compiler and figure it out. Right. Now, some of the settings for tslint are a little obtrusive. Okay. So we might need to tweak some of those, but I'm going to leave this tslint enabled. And I remember when we were clicking on some of these things it was giving us a tslint error. because it can't find the settings for that to see what tslint enabled, which is why it was telling you it was a problem, but you don't have any settings yet. Right, so just like the tsdconfig, we can look for a tslint.json example. It's a TypeScript thing but it's not unique to TypeScript as I said, there's a JSON, there's jscs, there's jslint, eslint, all these other linting tools, and we can just copy one of these files. There's a lot of settings here. That'll tell it kind of, how do you want it to look at your TypeScript. I have a friend of mine who says, Any time that I feel bad about your code, just run a linter against it. (laughing) I know. Tslint.json. And this is at the same level as our tsconfig. Right. because again, that's our TypeScript project root. So if we go back to... We probably have to tell it where the file is, maybe? I'm hoping that it searches just like the tsconfig. If you click on the settings there, what happens? Will it ask you where that file is? Search for tslint.json, looks for the file starting from the file's folder and then walking back up-- So it should find it. Maybe close the file and reopen it? I bet, I need to refresh this again. Oh, that's the editor config stuff, yeah. So I go back in here. Here we go. Okay, so he's not complaining. He's not complaining now. (laugh) And I don't see any warnings or errors, so. Cool. Now, I noticed something strange about your IDE. There's a triangle right next to admin controller in the left-hand pane, does that mean that the TypeScript file has a subfile for the JavaScript file? Yeah, it hides the compiled JavaScript for you so we can go and look and see-- And right now they're identical, right? Essentially it looks like some white space differences. Yeah. And we kept the comments, which is why they're showing up. This'll be good, because we can actually look at them side by side to see what is our TypeScript generating. Yup. We can get started converting these ES5, or what, um, 2014? (laughs) Yeah. Over to 2015? Yeah, we need to start doing that. At this point, just looking back, we've done a lot of work, but this was grunt work you do once. Right? You get your environment ready for TypeScript, and we were very careful to do certain things a certain way, we don't have to do everything we did. For example, you don't need the typings files, if you want everything to support Any, but we're going to get more checking, we're going to get more help, and as we start converting the code, the editor, because this is just like WebStorm, it'll tell us when we make mistakes because of the work we put in up front. Now that our environment's ready, yeah, let's dive into writing some code. Cool.
Watcher - Transpiling from Gulp
Watcher - Transpiling from Gulp
Okay, so we were going to jump into converting the JavaScript files or sorry, the renamed JavaScript files. But before that it'd be nice to get some visual feedback with my running app just to kind of make sure that I'm not breaking anything. Right, 'cause I assume you've already got a Gulp process that's handling all this 'cause I saw the Gulp file earlier. Right. Right now, to compile TypeScript, we're havin' to do it manually from the command line. You've got an IDE. There's probably an easier way to do this, right? Right. (chuckling) So why don't we make that work a little bit nicer. And if I were going to share this project with others or have them contribute, I wouldn't want to have to support a buncha IDE settings. Right. If I can have a common build process. Just by using Gulp, somebody could run a Gulp serve or a Gulp build, task, whatever yours is called, to make sure we can lint everything, transpile TypeScript over and do all that. Right. Here at the top of my Gulp file, I've got some paths. So I'd like to keep the JavaScript file separate because I have some tasks that still will run on those paths from the server JS. And since we're skipping that for now, let's make a TS lint paths. Okay, so you've got a JavaScript linter already, but now we're going to create a TypeScript linter. Right. Probably got some of the same code there, doesn't it? You're going to have to point your client code and your client test and things like that. Right, let me remove this from the JS lint paths and put this here. I assume you're moving that 'cause now you're not going to lint to your compiled JavaScript because that's not what you're writing anymore. You're writing TypeScript, so you're no longer going to lint the JavaScript. Right. Okay. Yeah, that generated code will likely trigger some problems with my earliest linter. Like in .NET, we don't lint our DLL's. (laughing) That setup should be all that we need. We might have to come back up there, but as I go down here, we've got clean, here we go, appScripts. So appScripts, is that looks like it's sucking in your source code using ng-annotate to stick in the injections for Angular, then building up... This bundles that app.js file. Gotcha. I had the vendor.js that I include and that app.js. This task bundles that together, running ng-annotate. Awesome. Bundling it into concatenating it. So it runs the script processing when it's done. Right. Gotcha. So here, we can use some Gulp plugins I had found to do the TypeScript compilation, just like we were running on the command line, the TSC. There's gulp-typescript and gulp-tslint. So let me just install those real quick. Yeah, while you're doin' that, I've used gulp-typescript. I've also just used the plain old TypeScript plugin, the non-Gulp one. Nice thing about Gulp is you can use either. So the gulp-typescript is good because that will use a stream. It take the files, put 'em in a stream and it lets you stream it from one step to the other through the pipe commands that you have, which is why that's good here. If I just use npm install typescript, which you probably already have, you could actually run that from, 'cause it's just code, inside the Gulp file. You could write node code to just run the TypeScript command and output the compiled logic. Right, yeah. In my research, I had found several different Gulp plug-ins. There's like, gulp-tsc and then yeah, the manual JavaScript method that you had mentioned. Right. And it doesn't really matter which one you pick. It's just what's your preference. Any way you do it, I think the nice thing about using gulp-typescript here is we're going to be able to stream it from one step to the other. I found that to be important because the IDE that's doing the automatic compilation of the TS files into the same folder, the JS folder, that can sometimes mess up the Grunt watch. Gotcha. As files are being written. Grunt or Gulp, yeah. Or Gulp, sorry. (laughing) Glunt or grope. (laughing) Or broccoli. Or brunch or yeah. (laughing) Come up with our own one someday. That's right. So cool, you've installed both of those? Yes. Alright. So those are there now. I'm using gulp-util. It just basically gives me this kind of jQuery-like loader for Gulp. So gulp-util use the loading, which says, "Hey, go ahead" and it'll automatically look up all of the Gulp packages that start with gulp-. Right, so I don't have to require them Right. all at the top, which is pretty convenient. It's awesome. A guy I know wrote a Gulp course, by the way. Oh yeah. Yeah, he kind of likes it. Should check that out. (laughing) I'm going to comment out these cached and remember plugins. These have helped me with bundling the JS files, so on changes, I don't want it to have to read all my JS files off a disk each time. Sure. Only the changed one. So those plugins help. For now in development, we'll get rid of it. Yup. So we want to look for TS files. Yeah, we don't want JS files anymore. We want TS files, right? Right. And we also have some TS files outside of source. So like our typings. Yes, we need to pick up the d.ts files too. So I can't use my variable there. I should just go into client and ts. That'll work. And then we'll keep ng-annotate. We need to use gulp-typescript. That would help. We just said we wanted it. (laughing) We should probably use it. So we want to pipe. Pipe means take the source files you just did, all the TypeScript and the interface files, the definition files. We'll use TypeScript. And the reason we know it's .typescript is anything after the gulp-. Right. So it's $. and then typescript. Now you've got to tell it where that project is. There's some parameters that we have to fill out here. Okay, because again, when we're doing command line, we'd have to either specify every single one of those options or we can just say, "Point to where my tsconfig.json is." So we've got basic usage here. So they're requiring it, just like you said. And we don't have to do that, yeah. We've already got it required. They've aliased it to ts. And we could list all the commands like that, but let's keep scrolling 'cause there's an easier way. We have a tsconfig JSON. Let's keep looking. There's got to be a way to tell it to tsconfig. Let me do a search in here. Right there. Oh, right here. So there is a TS project file. Actually, let's create. Oh. There's a whole section. There we go. If I just scroll a little further. Okay, so we create a project. Yep, you should be able to create that. We'll change the path to it, but that's fine. 'Cause yours isn't in the root. Yours is under client, yes. Client and then... So that just becomes the tsconfig file and then you can stick that here. Pass that in. Yep, and that's not going to be TS, though. Let's go back to your code 'cause we just copied and pasted. Right there, it says ts. That's going to be your $.typescript. Thanks for catchin' that. So now we sucked the files in. We're going to then stream it over to the tsconfig, so to do the compilation. And then everything else should just pick up where it left off, right? Right, it should just stream all that data through these Gulp plugins and create our app.js bundle. Okay. Why does that guy have a red thing at the end of the line? That's Oh, yeah. messing with my JSHint. JSHint (laughing). (mumbling) before. Use a linter and it'll make ya want to cry, right? (laughing) But yeah, that should run fine. We got that, but there's also a few other tasks in here. The linting. Right, 'cause we're not going to just lint anymore. So if you want to keep that one, why don't we call that jslint. Okay. Then we can create our own tslint. That sounds good. So tslint. We have the tslint paths from above. We already defined that, right? Right. So instead of jshint, tslint. And there's a reporter for that. Okay, not familiar with that one. gulp-tslint. Okay. So I notice you go write to npm and look for the code like that. Oh there we go. That's an easy way to find the syntax. tslint. So you're like me. You don't like to memorize syntax. That's right. Alright, 'cause we had the JS hint reporter. The reporter is, at least in JSHint, I assume it's the same in tslint, is a way to format the output. So it's more readable. Yeah, there's a few. It didn't look like it was as comprehensive as JSHint hints reporters. It's actually less things to find because in TypeScript, it's a little more structured. So in JavaScript is all over the place so there's more to find. So this one should be simpler. So I think that should be it. Yeah, we pointed it to the paths. I guess we're every we're running the linter too, right? So somebody must have been running this lint task before. Oh right. You probably want to find whichever task was running lints. You probably want to run tslint now. It's like lander this analyze. Yes, analyze. Okay. So lint doesn't exist anymore. Which also runs complexity. You can just turn that one off for now if you want. Yes. So client source for my complexity. We don't want to run that. Okay. So we'll change this to jslint and tslint. Okay, so it's saying run all those tasks, gotcha. Right. This is that gulp-run-sequence plugin that makes it a little easier to do the serialized tasks. Run one, then the other, then the other, then the other? Right. Okay. Yeah, in Gulp 4, you don't have to do that, which is kind of nice. They actually have a parallel and a series that you can do. But they're not officially released yet. So for now, run-sequence is a nice way to do that. I guess in this version of Gulp, everything is basically asynchronous. And parallel, yes. Right. You can give it the dependencies in the tasks. Yeah, it's a little more complicated to do series in this one. Yeah, it gets awkward. So we've just done that. So if we ran analyze, it should run all this, right? Yeah. Let's try that. You got a bunch of errors. So it's telling us we've got problems. So it's complaining about single quotes, it looks like, quote mark, we can adjust that. 'Cause I like single quotes. Basically, this is a list of all the things we're going to have to change as we go through it, right? Yep. So there's nothing wrong with that yet. That was expected. Yep. And then we can try. Do you have a watcher too? Yeah. (laughing) Read my mind. Oops, there we go. You definitely want a watcher because you're not going to want to type that commander all the time. Yep. Here it is right here. It's running lint so we will keep those paths. We also want to do our TS lint paths. TS lint paths. And instead of JSHint RC, we can point it to the tslint JSON so if we make any changes to that, it'll re-lint things on the fly. So take your paths of all your TypeScript and it'll use your tslint JSON settings. and then you're going to have to tell it to run the tslint when you're done, right? So the second parameter is what do I run when those files change. And then our watcher doesn't change for the appScripts because we didn't make any task changes. So the appScripts is going to watch the JavaScript or it's going to watch the TypeScript? Which one should ya do? We want to watch the TypeScript. Right, 'cause if we're not changin', yeah, that'd be kind of weird. (laughing) If you ran it on the JavaScript change, whenever you compile the TypeScript, it would rerun that again. (laughing) Yes. So let's have it watch on everything under client.ts. Okay, so anytime we change anything under client.ts, run appScripts. Okay. I'm not familiar with your entire Gulp files. Is that all we have to do to make the watch run? I think so. Let's try it. Nothin' like givin' it a shot. Yeah. gulp dev. We're going to see those errors pop up, right? 'Cause it should compile all that? On startup, it refrains from doing any of the linting, but as you save your files, it will trigger that linting. Okay, so this doesn't do the linting, that stuff you just did. But that just runs the project. Right. It seems to have run. As you refresh, it's there. It seems to, but let's... Just so we can make sure that it's all working here, let me get rid of all the JS files. Yeah, that's an easy way. Just to make sure that, no. Yeah, you marked 'em as plain text. That's probably not good. (laughing) That's alright. So we'll get all the JavaScript. We're going to delete it and this is just a quick way to make sure that we can compile from TypeScript over to JavaScript. Yep, ah jeez. Oh, and I don't want that one anyway. I know an easier way. There's got to be a terminal command to do that. There's got to be some command line utility. remove js. Alright, remove js gets rid of all the files that are js. And that didn't get rid of anything extra that we didn't care about? Well, I hope not. But thank goodness for get. Exactly. (laughing) So let's run this again. gulp dev. So no JavaScript was in the source folder. It didn't give us any problems. And it still runs. And it's still running. Good, so it's actually looking at the JavaScript because it can't run the TypeScript from the browser anyway. Right. Cool. Can we run the watcher real quick just to see if the watch task works? Oh, that is part of... That's from the watch part of it? Yeah, the dev Nice. is running the watch. Awesome. Yes, it's running watch and serve. So gulp dev runs watch, which ran watch up here, which is going to, looks like watch our TypeScript and run tslint. And then it's also going to serve the code, which then will serve and do all the transpilation. Is that where the transpilation happens? When's it going to get transpiled from TypeScript over to JavaScript? During the build dependency here. It will initially build it. It'll do the transpilation, make the bundles, put them under the build folder, which the server is pointing to to serve those files. Okay, because this one here is only going to tslint it, but this one here is going to, where did it go? Right there, that's actually going to do the transpilation for you then. Right. Gotcha, okay. Sweet, so we've got our files transpiled. So if we make a change here like under home and say what, Hi John. Sure. Oh. The file automatically redid it 'cause that's you're using browser sync, I assume? Right. Sweet. Awesome. So we've got that feedback now. I like that. Cool, so now we have everything set up so we can transpile on the fly. We can use Gulp to get all of our TypeScript converted over to JavaScript. And we've got a nice big list of things that we have to convert from JavaScript to TypeScript. Sweet. From the linter. And the nice thing is, this kind of setup, you could take that Gulp file and I guess, reuse it for other projects too. Potentially, yes. I noticed a lot of Gulp files, very opinionated. Yep, I've got my own, yep. There's different ways of structuring your Gulp tasks and maybe separate files. One of the yeoman generators, the Gulp Angular yeoman generator does that. So I would probably want to pull more things out into configuration parameters. Absolutely. Before I shared it. Yeah, it's all just JavaScript, which is what I love about Gulp. It's good is if you did this on multiple projects now, you'd be able to reuse that same stuff you just did on all these other projects. So you could just work on just the TypeScript to JavaScript parts. Awesome.
Converting ES5 Angular to TypeScript - Model, Config, and Controllers
Angular Module
Okay, so we can start with the app module. That's the easy one right? Easiest one, yep. And he's all red because of those tslint-ing errors? Yes, so let's see, if I hover over here, should be quote mark. Okay. Okay, so let me fix that really quick. ts-lint json quote mark. And it says double, I assume we change that to single? Single. We'll come back in here. Oh, we're in module. Wonderful, hey, it's perfect. Our job is done (laughs). So we got a missing comma, oh. Why does it want a trailing comma? That's strange. That's kind of neat. Though, I mean, if you, you know how we can just leave it with a comma and then-- Right. You know, as you add more things, you don't have to worry about that trailing comma. Yep, and this is TypeScript so we can do what we want there. So in TypeScript, we have, it's giving us function issues there, right? Right. That's okay, we're going to get rid of that anyway. Yep. So we're not going to use an IIFE. We use an IIFE in JavaScript because we need to make a closure but in TypeScript, there is a concept called a namespace. So we can remove that function and put a namespace up there, over the namespace key, yep, and we just call this app or reader or whatever you want to call it. I usually use a short name like that, and then curly brace. And then go to the bottom and get rid of all that other stuff. And if that transpiles, is your transpiler on right now? Yes, so if I open this up? You see, what it generates is very similar to what you had before, other than it's a slightly different version of the IIFE. So now, it creates some global variable app so your namespace is a global. So you'd have to use something that you are sure nobody else is going to trounce on, like maybe something more descriptive than that. Right? Right. We'll use that for this one, though. And then it basically uses that to create an IIFE Immediately Invoked Function Execution, or Expression to create that closure for us, so everything that's used inside of that IIFE is a local variable. And this doesn't make as much sense here in the module file as it will in the other ones. Right, we could potentially assign app you know, assign the Angular module to app? Potentially, if you were going to do like, instead of namespaces, using the external modules? Yeah, you could create a global, that's the name of the module, it angular generates, so you could share that around too, cool. So, is that it for this one? That's it for him. Why don't we just go to the controllers next? Okay, or, or there's also configs. Yeah, let's do the configs. It's kind of base-level, or working our way from the inside out. Sure.
Angular Configuration Blocks
Let me pull both of these up, too, so we can watch. Okay, can we make this bigger? Yes. So I can see some more stuff? Sweet. There we go. Awesome, so on the left we get the TypeScript, and on the right we've got what it's transpiling to, which are identical right now. Right. So we should start with the namespace thing again. Do that again, namespace app. And go to the bottom, yep. Get rid of this. And now it should generate on the right-hand side. And it did, good. So it's reusing that global variable for us, which is fine, Okay, and now the Angular registration is going to be fine because that's just the name of the module and we're going to call these three functions. The cool thing about TypeScript is, you don't have to use classes everywhere, so TypeScript offers classes, but we can just take advantage of using functions. In some cases, functions are easier. Like the first function its got, is called, init debug. There's really no advantage to turning that into a class. Right. So we're just going to leave that alone, and let it call like it is. The interface for this guy is just a function. Mm-hmm. So, yeah it makes sense just to leave it as such. Now if we wanted to get debugging, we could actually put a type on him, so the compile provider, we could say, dollar sign compile provider is colon of type, it's probably angular dot I something. I compile provider. There you go. I like that tooling. And that whole function, see how it's red at the end of your little, yep, so we do a colon at the end of that, and say this function is a type void, because it's not returning anything. So that would basically, we've TypeScript-I-fied. We've TypeScript-I-fied our code. But notice on the right-hand side, nothing changed. Yeah. Types don't transpile, they just give us type information and tooling in our TypeScript. And again, we have the comments turned on so it's preserving that, it's not mangling that at all. Exactly. Cool, so the next one, we can do the same type of thing. Yep. You're right, so angular, oh this line might get long here. Angular I location provider. Yep. It'd be Enter. Yeah, oh nice, okay. I'll do an angular I router provider. Oh you know what, that's part of the angular UI, so it's probably angular dot UI, yeah! I URL router. Yes. So it'll take some just getting used to where these definitions are located within the Main space. The namespaces of the definition files. I just happen to know that angular UI router has got its own namespace of angular dot UI. Dot, so that's how they separate out they're stuff from angular stuff. Router, URL router provider, that's the one? Yep, then you've got your state provider, which is also part of angular UI. State provider. There we go, so now you've got your parameters have types on them, which means then, if you hover over your URL provider right there, it should give you the type, on the left, yeah. Right there, so if you hover over him, you're assuming your editor will tell you what that is. Not so much? Kind of like in VS, splitter will do that. Right. There's no way. Go to definition review, types. Go to Type declaration? Right, and it's going here, signature there. So it is finding each other right now, cool. All right, now we've got a state provider, and it's telling us it doesn't like what template URL is, and the other stuff there. Unsorted key. Object literal sort key. Oh, tslint, you must have a setting on, where your keys must be sorted. Okay, let's turn that off. Yeah, that's awful. All right, so somewhere in there is going to be there's going to be a sorting or an order. Member ordering. Is it member, or, I already forgot it. Objects literal sort keys. There you go, turn it to false, 'cause we don't want that. We could also have gotten rid of that tslint if we wanted to, so these are options. It's going to help us find some things, like these ones are obviously not very valuable, so we're just going to turn them off. And this one. So you got to go back to app, config. Let's turn this trailing comma off. Okay. Trailing comma. Always on multi-line, we'll just do never. Sweet. Okay. Let's go back to app config ts. Now in our state provider, we've got a state and we're still passing in an object literal to the state, that's perfectly fine, we don't have to use classes there either, so that should be good for it. It's complaining about white space, I believe. Oh, white space, there you go. So all of that looks fine, those are just objects with methods. Now let's go down to init storage. And do the same thing with the local storage provider. Now this was part of our ngStorage definition that we created, and that was ngStorage. Right, we created this one ourselves. Yep, I localStorageProvider. Perfect, I think it will be a void because you're not returning anything. Yep. And set key prefix, fine. Oh, we can use let. We can, so in ES6 or TypeScript, you can use let to say, create a scope inside a function for it. You don't have to, but you could. So we could do let readers, now, is the problem there that readers is a different type? This problem is that our linter is forbidding the var key. Oh really. Altogether, yes. Okay. Which is neat. Sure, we can turn it to let,'cause let's a little more restrictive. And then this error, expected variable declaration. Okay, so it wants us to tell us what this thing is? Right. All right, so readers is going to be, what is that? We could do any right, just do cheat or see, readers. It's getting a list of readers. Is an array. Okay. It's an array of these, these simple objects with IT in them. Okay, so if you wanted to get intellisense in those objects, we could create an interface, or a class of type reader. Okay. Of our own, to do this. Want to do the here for now? Sure, just like we did in the other one, but without the declare? Yeah, yeah, just create a regular old interface, and you can call this thing I reader, sounds good. I reader. Then you got to give it properties like we know it has an ID property, right? ID, and the syntax I'm still getting used to, but I would just do ID String, just like that. Yes, it's an ID of type String, and so that's how that reads, and then you need your little semi-colon. Yep. So that's our interface, and then down below, where it's let readers, the type of that would become array of readers, which is Capital Array. With the generics, right? Yes, using generics. I reader. Exactly, so that does that. Now that works because the property, see down below, inside your if, you've got those ID properties. All those are of type String there. Just for example, change the ID in the interface to number. Now it should tell us down below, that, hey, you know, if this thing wasn't set there, we'd have that problem. Well, the localStorage provider, remember, is taking any. So he's taking any, so he's not being as restrictive. But your readers are actually telling it that. But if, I could do something like this, right? I could cast it to array of type I reader. And will it complain then? Well, see if your editor likes that. So you do that there, and you've got him. It's another type String I reader. Okay, what I would probably do instead, is get rid of the array I reader. And instead, for each of those objects, we can cast each individual one to reader as well. Oh, gotcha. So each one of those would work. We know we're going to be safe, though, so I don't know if I'd worry about it. Gotcha. At this point, we just know that, that guy is going to be an array, and it's going to contain something that matches I reader as an interface. Cool. Now, go ahead. No, I was going to mention that these are used elsewhere in the app. Oh, are they, okay. In our directive, later on. That makes sense. So we could potentially reuse this interface there. We're going to need to take it out of this, well we don't have to take it out of the file. It would be easier. Why don't we make our own file, for reader dot ts and stick that interface in it? Our own file with this in it. Yes. So pull that out. We could stick it right at the same level as app. Like I reader, or? Yeah, just call it reader. Dot ts. You could call it reader interface, reader class, reader model. Right. Generally what I'll have in a project is, I'll have a model folder, and I'll stick all my readers, or maybe it's like customer's orders details. And we'll wrap this in a namespace, too. 'Cause we want it to be in the same namespace. So it'll be namespace app. Good catch. So the advantage of this is, it lets us have all of our models, which in this case is reader, be in once place. Either in one file or some people just create a models file, and they'll put everything in there. And that way, everybody can kind of just, you know, use that for intellisense. U strict, yep. Now that interface is now private to that namespace, we want to use it somewhere else, so we're going to say export the interface. That says, hey, it's not just usable in this, it's usable elsewhere, so it will go back to the other file we were in. I forget which one we were in. App config. Okay. Let's scroll down and take a look at him. The I reader is still being used, it should still know what an I reader is. Yep. Perfect, now we can share it. We don't have to import the file, or anything else because the TypeScript compiler is looking at all those files in that folder. Cool, so another file down. Yeah. All right, we're on a roll. The next one, yeah, one of the controllers. Okay, why don't we hit the easiest one first? That would be home controller. That certainly would be that one, wouldn't it? There's not much in there. All right, so namespace wrap it? Namespace wrap. Now so we're saying that TypeScript has modules, like module orders, like ES6 does. So we could actually define real modules and export them and import them all over the place. That we could do, but this is going to be like the first step, let's convert it just using using namespaces first, because it's sticking with the IIFE guidelines, because if we use real, like node modules or common JS modules, what we'd have to do is have a module loader, like webpack or System JS or Browserify, and that's a little more than we want to do right now. I'd like to get early wins, and see it running. So we'll just do the IIFEs, and then let's take a look at that controller, and see is, do we want to keep that as a function or we want to turn it into a class.
Home Controller
I'd like to see it, see a couple of classes here. How about you? Yeah, I think a class seems appropriate here. Okay. Especially in some other of the controllers that I've seen, you might have other methods there, that you might bind to the-- This'll be an easy one to do, because there's very little in it. So we can get the idea of what it's going to look like. So why don't we just keep the function there for a minute and put a class above it, just so we can show them side by side. Okay. And just create a class called, Home Controller. And yep, your little guy is there, yep. And just for now, rename the other guy to Home Controller 2, or something, the function. Just so we can see them without it complaining about-- Yep. About that. And in there, you want to copy what you've got, effectively, so you've got a constructor. Right. That's going to define where it is. And this is how you inject things. Local storage. Yep. And this is going to be, no that's ours. That's your ngStorage thing, right? Yep. I localStorage provider. Now that's going to be your service, isn't it? Right. Is it I service, or just service? I storage service. There you go. All right, so you constructor, then you can set your, looks like you got a local variable called, Storage in there, it's not really local, it's a property on the controller. Right. So inside the constructor, just do, this dot storage. I can define it up here, right? So it says storage, which is of that same type. Yes. Just copy paste that. And make that public, because. Yeah public, but I like to be explicit. Because then I don't have to worry if it's public or private. Then the hinter, the linter was complaining about it, too, default access method not allowed, so it wants you to be explicit. Yep. Public. I like it to be explicit, too. Yeah, okay, so I got, there's some white space here. Maybe we want to just do this, storage equals local storage. Yes. So that gives you your constructor, and it gives you your public. What's the red line up there for? That's white space, it should go away here when I Save it and clear it out. That is kind of annoying. So we've done a couple of things. Notice we didn't do a VM this time. What we've done, the VM was just capturing this. We don't have to worry about that any more. And this dot storage, it's an instance property on the controller, so it's a property in Home Controller called, Storage, that we're referencing or setting. There's actually a shorter way of doing this, too. Want to take a look. You can actually delete the public storage lines. Get rid of that for a minute. There you go, and put the word, public, in front of the word, dollar sign local storage. So if we do that, we can actually go ahead and get the guy and make him, we could do some instance variables and other stuff, but we want to actually set a different property here. So let's keep what you had instead just to, because, to keep the syntax going. So just Control Z it twice, and we'll be good. But looking over on the right side, it actually did, it did the shorthand for us. This local storage equals local storage. So if you want to keep it super short, just change that variable name to, storage. In the parameter list. Oh, gotcha. And get rid of the line right below you. And now, if we look over at transpiles, you'll see what happened. I'll just need to do my, oh, that'll mess up my ngInject, then. You'll need your ngInject here. But it's going to look for storage, which isn't going to match the localStorage. Exactly, so that's where you've got to do the inject, yeah, we have to do dollar sign inject. So this, if the name matches your find, because your names are different, we're going to keep them the way your code was. But if you wanted to change your name, wherever you're using it, to the other name that would be fine, or we'd have to map the ngInject. I think the simplest thing in this case, want to get running, is just to do what you had. Without having to go into the templates. Exactly. And having to change that name around. So, that'll be good, and if you'd like, you can still put your dollar sign, dollar sign, your @ngInject above the constructor. Oh right, I will definitely need that. That way you can find it. So that template, look up ng, template's pretty good at finding stuff even without the comment, but why not? True. Why not just leave it there, make it easy. And now we can delete the function on the bottom. We don't need that at all anymore. Let's get rid of this. And get rid of this. Yes, we have one tiny problem now. In JavaScript, ES5, it's okay to use a function before you define it. For example, this Home Controller up here, can be used, it's being used before it's being defined. In JavaScript 5, that's okay, in TypeScript it's not. Because now when it does the JavaScript, on this line up here, use Home Controller, but then there's a var called, Home Controller. And that expression actually stays where it is. It doesn't get hoisted. So these two lines have to be flipped in TypeScript, so you have to put your angular module controller definition below the class. Gotcha, so if I, if I ran this. It's going to tell you, I can't find Home Controller. Or undefined Home Controller, something like that. Right, and yeah. So we're having a problem. Home Controller's not a function. Not defined, okay. So that's why, TypeScript decides that it's not going to use the function expression, like it did over here, instead it's doing a variable declaration. Which actually happens, is Home Controller gets hoisted up. So we need to put that class above. Yes. Exactly, now if you look at the generated code, Home Controller exists by the time it's used, so therefore you're okay. And now if you run your wrap, you should be able to run. Look at this. Restart. Yep, and there it is. Cool, it's still working.
Admin Controller
So the next controller. Yeah, let's go look at your other dude. The admin controller. All right, so we did the Home Controller. Let's go to admin, and we'll do the same kind of syntax UL change. Put that guy over there, so we can watch it. All right. Okay. So we'll change the IIFE again, to a namespace. Yep. Why don't we move the angular module controller stuff to the bottom, since we know that's going to have to go to the bottom. And now we'll put the class up top. I like to leave the function there as I'm doing it, just so I can see what's happening. Controller. Just name it 2 or something. It's going to go away. And. Constructor. You're going to pass into that the localStorage. Right. Storage service. That works. For this one, do you want to try the other injection syntax? So we don't have to create the property, called, this dot storage? Yeah. All right, so we know you wanted to call it, this dot storage, which is down below here. Instead what we could do is syntax, just like in Angular, we're in Angular 1. In JavaScript, we have that inject, the dollar sign inject. Right, you could do admin controller to dot inject, right? That might work for it, but I know what definitely will work is above the constructor but inside the class, we create a static property. I meant just in regular ES5. Yeah yeah, yeah yeah. You would use what inject equals an array? Yes, it would be an array, and it's the name that you want, the dollar sign local storage. So that would be, we would just be-- It would be that guy right there, yeah. Local storage. Yep. All right, and then we could rename this to, storage. Right. So we want to do the same thing up here. Yes. Above the class? Inside the class, above the constructor. Above the constructor. Because it's actually a static property on him. Okay, so I could go with static properties. Yeah, it's neat, it's effectively what you did down here, if that was ES5, right, so it's a static property on the object. Because everything's an object. Your admin controller in ES5 is an object, even though it's a function, and you could actually decorate it with properties. Which is what we did with Angular 1, with the dollar sign inject. So up here, the way to create a static property in a class world, is to, inside the class, define static, it's got to be called, dollar sign inject. Dollar inject. And we'll make that a type, array of Strings. All right, I didn't name it correctly down here, it is dollar inject, right? Yeah, so colon, array. Of strings. That's right. And then we'll set the equal to. Oh, 'cause we can initialize it right away. Exactly. To the same thing. Yep. Local. Local storage. And then a semi-colon. Perfect, so now you can rename inside the constructor, the name you actually want, which is storage, I think. And then do the shorthand. 'Cause you want to make a public, that's how you do that, yep. And, boom, it did that. Yep, so now you've got that, and you'll notice the inject is in here. Cool. So now that's what you'd expect in JavaScript ES5, and now you've got the same kind of code, it just the TypeScript syntax. That way, you don't have to have anything inside your constructor. You can actually get rid of all the white space in there if you want. Like my syntax, usually just curly brace-curly brace, for example, to save some space up there. Oh, just like that, if you didn't have anything else. Yeah there's nothing in there. Just setting those, gotcha. So that's all our constructor's doing, I think. Well, we've got these other methods here. Right, and those are below the constructor. Right. We wouldn't put that inside the constructor. Right. So we would have add reader. Yep, same name as the function. Public. Right, with looks like void with. Does it return anything, no, so it's a void. That works, and then you put that same syntax in there that you had for the other one. So this, storage. I forget I can just just copy-paste. Yes copy-paste is good. Public. Remove reader. And here, we're passing in an index. Yes. Which would be a number. Okay. Or a String. We can do that UN stuff. Yep, that's a union. Or you could do any, if you really don't care. Right. So it's up to you. Then you put your same code in there. Right, you don't need a VM any more. Just do this, and paste. Right, let's delete your code at the bottom, so there's no more, because I think we're all done with that, right. Yes. And check over to add our app, because it's still looks like it's still working. Still there, nothing error'd. Let's go back and look-- We're in the admin controller, though, on this page, so. This exercise is the add reader, and remove. Okay, so your code's working, and there's no errors popping up on the console. So we're good. So back in the code. We can see, let's look at the JavaScript it's generating and make sure we're happy. Notice it's slightly different than what you had before. Now you've got storage, which we did the inject, so that's good, but you've got your add reader and remove reader, which are now prototype functions. So the advantage of this is, if you created many, many instances of admin controller, the prototype only creates one of each of those methods. We know we're only going to do one. Right. Controller, so it doesn't matter. Much, right. But TypeScript, that's just the way it generates the codes, so that's good. Now we've got a couple of red underlines over on the left, let's just take a look and see what's going on. Readers doesn't exist on the storage service. On the type storage service. Okay, so your storage service doesn't have that particular thing. That's where we could have some kind of a typing problem inside of our I storage service, we could take a look at that? Well, we haven't gotten to that storage service yet. Oh, then that's why, we haven't gotten to him. Okay, so I thought that was because the type, though, the I storage service might not be right. Oh. So do we, we defined that file. Let's go take a look at that ngStorage file, that we created, the typings file. That ngStorage, that is, we did get to that, yeah, we configured that. I was thinking of the reader api service. Right, we haven't done him yet. Right, so in the typings, ngStorage, we had key string, any. Okay, so if we converted that to, instead, back in the admin controller, if we converted this to not a property, but like an array key? Is it going to complain? Let's see now. Object access via string layer. Okay, so we're bumping into some, we're bumping into the definition that we've created. Right, the definition is created. Versus the tshinting, so I don't mind string letter rolls, so let me disable that. Okay, that works. Those string letter rolls. So tslint, we're going to tell it, hey, it's okay to refer to properties. Drive string literal. So if you wanted that on, we would-- Have to change the type definition. Make sure everything is, has a property type. Okay, back in the admin controller. There we go with him, he's not red any more. And we can-- Do the same thing. Yeah. And we could change that around, that's fine. We just want to make sure we're happy with him. And also let's find out why public is unhappy. Let's see here, what is it saying? Tslint (laughs). Storage cannot, what? Be declared in the constructor. No constructor-- Oh, that must be a setting in tslint, because that's absolutely fine in Typescript. So let's turn that off in tslint. I'm not liking tslint so much. I know, it's getting in the way. No constructor vars. All right, let's go back to code. And that one should go, good! Static's probably another one. Static default access modifier on member not allowed. Access. Okay. We want to allow that. Okay. So one more, we're going to turn off. Good news is, we turn these things off once, and they're done forever. Oh geez. What was that error message again? It was in admin. Default access modifier. Member dash access. Oh, it tells you exactly where it is, good. Yeah, it's this guy. Cool. Okay. Admin controller ts, all of our red lines gone. Yay, and notice none of that affected the output of JavaScript, the output of JavaScript was happy with all that stuff. Just fixing that last one. (both talking at once) Cool, so we've got the controllers, they both work, what other files do we have in this project?
Reader API Service
We did the module, we did the config, we did the controllers. We did both controllers, now. What's the next easiest? We've got the service and the directive. All right, let's go to the service, that's easier. Yes. So open that up. I'm sure he's going to need himself a namespace as well. Yes. Cool, I'm going to move the Angular part to the bottom, the angular.module. Right, because the service is a good candidate for a class, too. Yes. And we'll make this a class. Yep, class reader api. I like, I like what you, that tip there, where you keep both of them. Yeah, you kind of get to see. When you get faster at it, you'll just overwrite the function as you go. But when I have larger ones, it's kind of nice to see what I was doing. Yeah. So it was kind of an easy way to go about it. Like, it's okay, a contructor, a contructor, yeah, constructor. And you're going to inject http, that'll work. There's an Angular I http. Yeah, it's going to be http. Service-- Service or factory or provider or thing. Yep, and that constructor's doing nothing. That's just to inject it. Now in this one, you don't have to do the, the static http stuff because we're just going to call it dot http. Oh, okay, so I can do the, I can do the public here, right? Yep, do public there, and you automatically get that guy. If I look over here, yes. This, http, so now we're, we can get into these. Exactly, just copy those guys up there. I'll bet you it will be a really simple conversion. So. No more of this. You can do public if you want to. Right. Get rid of the equal sign, and the word, function. Awesome. Reader ID, I assume is, it's a String. Okay, and if you're ever not sure, just put any. Right. Just to get it moving. Get rid of the reviews, and this is going to be a promise. Okay, Angular has one of those as a type 2, so we can do angular dot. It might be dot q, or it might just be iPromise. Let's see, yep, good. So, dollar sign q is in Angular, and it exposes promises. So that's that type that we use there. And then, good, so we're going to return http. But it's not just http now, now it's a property on the class, if you return this dot http. I'm getting an error. I Promise requires a type argument. Oh yeah, because it's got to know what's coming back in the promise. So do the alligators, yep. Like just, any? Yeah, for now that's fine. We could say what exact type is coming out of it, like a String or an Object. And then we'll do return this dot dollar sign http. All right, we'll go in there, we'll check our properties. It's going to want to know the data type of the result in your then. So you see the, then, there? Right. It's saying, hey, what type is that? And that thing has a property called, Data. So just create an Object Literal. Oh, that's like this, right? Yep. Put data. Data colon, just do any. Any. Yeah. Yep. 'Cause you don't know exactly, if you wanted to say, well this is always coming back with a review object, you could create an iReview interface, and then you could say it's returning back a result of iReview interface. If you wanted to. Gotcha. But we can just do any, for now. And this could be a good candidate for a lambda? Yes, that ought to be great there. So you got him into the arrow. And then that way, we're not forced into, I guess with the linter-- You could actually even get shorter. If you get rid of the curly brace after the fat arrow. And get rid of the word, return. And then get rid of the other curly brace. And put it all on one line. Oh nice. And then pull your guy up, and get rid of the semi-colon up there. I think, I'm sorry. The semi-colon after the data. Semi-colon after the data. Yes, now you got a missing-- I'm missing something. Parentheses, you think? There we go. And then that one, maybe two parentheses. Does it show you parentheses matching? Yeah, there we go. Yep, that looks right, it's just white space. Now it's just white space. Yep. Okay, so now you've got your lambda saying, hey, after this is done, we're going to give you a result back in a parameter, and we're going to return the result dot data. And that's just an advantage, so now if you look at the actual code right now over on the right-hand side, it's the same thing we wrote before, it's a function that passes a result and returns result data. Nice. Just a little trimmer. Yeah. Cool. And I notice this stuff here, the string templating type of thing that you can do now. Template strings, yep. It's kind of like this. I'm thinking back to my PHP experience. Yes. You do that, and you have to change the Strings to back-ticks. Back-ticks. So now you're saying, it's an ES6 thing. You're saying, that's still a String, but replace anything with a dollar sign curly braces with a property. Or a variable. So now that'll say, api reader slash whatever reader ID is, slash reviews. Is that the right syntax, I mean look on the right. We can see here it's URL, that plus that. Yeah. Yep. Cool. It's always good to make sure that what you see on the right-hand side is what you expected to see. I keep forgetting to look over there, yep. So let's do the other function now. So I'm just going to, this is probably closer than the other one. Okay. So api readers. Plus it reviews, but it had the same kind of structure with the result data being returned. Okay, and it's called, Reader Info. Get reader info. We're passing in a reader ID, yep. And we still return back a promise of any. Yep. It's a get, it's api reader is reader ID. Good, and the data is the same kind of result, yes. See that's another reason, if you want, we could just use data any, we could do it, like, an I Result up top, if you wanted to, it's really not going to help you much here. We could create something, because we're copying and pasting data, any, multiple places now, so we could just create an interface to do that. Right, yeah, we could get, we could use the schema from... Yes. From the back end and define that. Exactly. As an interface, is what you're saying, gotcha. Yeah, we don't have to keep defining it on the fly. This is just saying, hey, that result happens to have a property called Data on it. Just so that the compiler's happy. Gotcha. Sweet. Let me remove all this other stuff. And I haven't checked the app in awhile. Yeah, let's go see if it still works, man. Okay. If it's getting data, it works, right? It's working, yep. All right. Still getting data. Awesome.
Cleanup
I've been pretty happy with how things have moved along so far. But one thing we got inconsistent on, and I like to be consistent, is we had a Home Controller and an admin controller. And we did injection in a different way. So let's go to, I think it was admin controller. We used the static, so in Home Controller, let's also use static. Okay. Let me copy that really quick. It's the same, exact syntax, right? Yep. And it's the same thing we're injecting. So now, by putting those two lines in, we're declaring the static and the constructor on one line, and we don't need to say, public storage, and we don't need to set the property inside the constructor. So remove that, and just, yeah, looks exactly the same. Yeah, and that's TypeScript in action. It's just making your life a little easier. 'Cause otherwise, you have to say, declare storage, inject storage, and then set the injected storage to declared storage, and this is just saying, you know what, just please set this up for me. So it's a little bit cleaner and easier, and the code on the right should work, and if we go run the app, it should be running, right? Yep. We were in the Home Controller. And then the admin controller should still work. Yep. Wonderful. I think I said, the code on the right, if you're intelligate, but that was reader api, I think. Oh. But yeah, it still transpiled the way it should. Oh right. So you look at-- So the Home Controller, yep, yeah that looks right. Perfect. Cool.
Converting ES5 Angular to TypeScript - Directives
Function Returning IDirective
So we've got our service, we've got our controllers, we've got our config, we've got our module. Now we have the directive. Yes. Alright. Let's get that guy. Okay. Some side-by-side. We can take a look at these guys. Let's do the namespace again. Getting to be a pro at this. (Chris laughs) You could probably do a global search and replace. Yeah, obviously we could do something like that. Now, in a directive, we could use the function or we could a class. This is one of those places where I find that directives, because the way that they're set up in the link functions and how they're used, creating a class doesn't add a ton of value. 'Cuz you're not creating an instance of it using the properties off it, you're actually using this DDO. The DDO is a Directive Definition Object, and that's that thing that you're returning from the latest book reviews directive. Right, this is like a factory function. Exactly. It's creating that and returning that object which points to everything else. So we could turn that into a class, but honestly I'm going to tell you that it's really not worth the trouble. But we do have to do a couple things to make this work. First, like you'll notice, the transpiled code, it's putting the latest book reviews directive up here. Actually, change something in this 'cuz I want to see it. I just want to make sure it's actually transpiling for us. Like add a var = x or something. That'll work. I'll do a let. A let! There you go. You're going to let x = 0. Good. So now we see our var. Except there. We both got what we wanted. Awesome. So that directive is pointing at him. Notice, it left the function alone down here. Notice on this side, that the transpiled JavaScript said let's use this directive. It's called latest book reviews directive, and it's telling go use the function down here. It didn't turn it into a var latest book review directive equals function. Alright, 'cuz it's not a class, it's still a function, so we keep it a function. It's going to leave it exactly the way it is, which means you could keep this at the top if you wanted it to. Or, you could move it to the bottom if you wanted to be consistent. It's really up to you. So if it's a function, you're fine. It's not going to worry about it 'cuz this is actually going to be hoisted, literally lifted up above the angular statement, to the top. But because your code is staying as a function, you're fine either way, so you get to pick. Okay. I'm just going to move it because I like consistency too. That's good. You just got to figure out which curly brace to put it after. Yeah. I think you did it right. And can we please get rid of this?-- Trailing white space? Oh gosh, yes please. I wasn't going to say anything, but.... (Chris laughs) It's not my editor of choice, but those trailing white spaces, wooh! False. I don't like red lines everywhere Right. Alright, so go back in the directive. Sweet. Now we have to give some types to things. Like, the Reader API. So we know what that is, right? Right, that's our service that we were just in. Right. So you should be able to say, "Okay, I've got a Reader API service." So you put in there just Reader API. Now, it still has a problem with that. So hover over that, we'll see what the error is. Problem here is it can't find our service. So, the reason it can't find our service is it's in another file, in another module, effectively. And it can't figure out where that is. So we have to go back to him, that other service. It's called Reader API, right? Yes. Reader API service. I'll put him over here. Yeah, let's do that. There's a couple ways we could tackle this. We could just export that class for the Reader API. Export this class... Mm-hmm, we could do that. And then if he's exported, that means somebody else can actually see him. So the guy in the other file should be able to see our Reader API as long as we export 'em. Yeah, he's not red anymore. Okay. And what's that little last red piece then? That is call signature. Okay. It's not-- Just to fix that really quickly, there's an IDirective, I think. Yup, that defines the IDirective. DDO, what did you call that again? DDO. Directive Definition Objective. Yes. Cool. So that basically, the reason that was there, is because you're returning an object at certain types, and now this thing says, Hey, it's got to have certain property structure. It does that. So, one question. We exported this here. This is, like, the first time that we've had to use this, I think. Yes. Then why didn't we have to use this for the controllers? So that's a good point. So the admin controller and the home controller, we never import them from anywhere else. So we're not using them anywhere else, so we don't have to export them. We're just using them right within their own file-- Yeah, take a look at admin controller ts somewhere, for example. Or home controller. Yeah, we're just using it here, so we're not referencing it elsewhere, like how you can share controllers around with directives and-- Yes, that's a good point. That might be a case where you'd want to export that class? Yeah, and some people have said in the past, like if you have a directive and it has a controller, like I don't think ours did actually, it might or might not, but if you have a directive that has a controller, if you wanted to separate those into different files, a directives controller, that's one way you could do it. With typescript. You could say, "Create the directive for the controller over here", sorry the controller for the directive over here, the directive over there, export the controller, and then he could read it. I like to keep them in the same file in that case, but... Yeah, we don't have a controller here, we only have a link function. Yeah, and he's fine to be embedded the way he is. The other thing we could do is we exported a class, but remember, I think it was in the reader model we created, reader.ts can you go back to him for a moment? Yup. We exported an interface here. Look at the transpiled code for the reader.ts. Go to reader.js. reader.ts, reader.js. Yes. Nothing. Nothing. So what's happened is an interface does nothing. The only thing generating that code, actually is the namespace. So if you go back to reader.ts just for grins. Can you remove the namespace at the top? And get rid of the last curly brace. Cool. Now go back to reader.js and look at what happened. Literally nothing. (laughs) So what happens in interface doesn't generate any compiled JavaScripts. The advantage of doing an interface here instead of a class, yeah put back your code, is that class will generate some code, whereas an interface won't. So change into a class for just a moment. Say, export class ireader. And we'll just call it ireader for now. Now look at your reader.js again. Now, it generates code. So what do we really get here? An interface generates nothing in JavaScript, it's really just for tooling and compiling or transpiling. The class, we'd only need that if we were going to new-it-up somewhere, like we were going to create a new instance of a reader. Which we could do, like a reader, or a book, or a customer, whatever we might have. Because we don't want to add extra bloat to our JavaScript files, we're not going to create a class. We're just going to make it an interface. So that's why we'll go back to reader.ts and we'll change it back to export interface. Perfect. So why did I go through all that? Let's go back to the reader service for a minute. We made that a class called Reader API, and we've exported a class in this case. You can export interfaces, classes, variables like lets. Another option we could have is we could create an interface for Reader API. So we could define a Reader API interface, and have the class implement that. Let's do that just to show that syntax too. Sure, we can do that above here. So, interface... And we'll probably want to export it. Yes. We'll do IReader API. Some people don't like "i"s in front, I kind of like 'em. There's somebody we both know who doesn't like "i"s in front of their interfaces. (laughs) So, I can basically borrow this whole first... Give it a shot! Worst thing that can happen is that it doesn't work, right? So, nothing will fall apart. Also, let's just make this clean too. Get him. And then, on the class, don't export the class anymore. Just keep the class without the export statement. Keep the class without the export statement. Right. We no longer need to export him. And now, let's fix the interface. There's no public in the interface. That's just the name of the thing. So there's your interface. Now down below, do Colon. Alright, not Colon, I'm thinking of C#. Implements. I forget which language I'm doing half of the time. IReader. Yup. So now, go up top here and just change the name of the function from getReader to-- Impose. So we do that. Now hover over the class reader. It says, "Hey. You forgot to implement that interface." Now when you implement an interface, what you're saying exactly now is that class has to implement both functions, get Reader reviews, and Reader infos. It doesn't mean though that you can't add an additional function. So that's fine. It's just the minimum that class has to support is those two functions up top. Gotchya. So you're saying if I copied this and made it info z-- You're now satisfying the interface. Yup. And that way you can implement multiple interfaces if you needed. Yeah. And you could have other properties on here and do all sorts of fun things. But let's get rid of the info z's because we certainly don't want that. And we'll fix our interface up top. Now what we're saying is, "Hey, we're going to export this interface," and if you look at the compiled output it's not going to have anything different, 'cuz there is no such thing an interface in ES5. Let's take a look at his transpiled Reader service. And you'll see there's no interface to be found. No interface there. Right. These are of prototypes. And now that we've changed the Reader API service to using interface, let's go back to the place we used it. The directive. And now he was referring earlier to the class that we exported, which we're no longer exporting the class called Reader API. We're now exporting the IReader API. So this is a convention I like to use where I actually like to define my types with interfaces in general. You don't have to, it's just a convention I do. I'd rather talk to the interface, and that also helps me so I can use that code in other places a little bit easier. Mm-hmm. Makes sense.
Type Casting Reader from Scope
So we've got this return object-- Or DDO. Yes, our DDO. Dance Dance Object, Dance Dance Revolution. (laughing) Latest book reviews link function here that's throwing some expected parameter types. Yeah, once in a while, these things are. So scope is an angular thing, so lets do :angular. There's probably an iScope. Yup. Okay. Now, are you using elementer adders? I'm not, so let's get rid of them. If you didn't want to get rid of them, you just do element:ne or you could actually go find the... let's just try it real quick. angular.ielement Maybe it's directive element, maybe it's DOM element. Try DOM element. There's some jQuery, augmented jQuery. Okay. So we can go into him too. So we could define our types, but we're not actually using these though so let's just kill these two guys. We could also do ne by the way. So that's the nice thing about it, until you're not using these parameters, don't bother. So now we've got the iScope in there, and it's still red. What's the red part? Oh, so you can tell what type it is, okay. Just void? Yup. In this case we're not doing anything with the link function, are we? We're not returning anything, no. It's just setting everything up. Okay. So now we've got Scope. Now here's one of the problems. When you've got Scope and it's got properties, one of the reasons I don't use angular iScope is because now notice it doesn't like scope.reader or scope.reviewdata or render reader model. There's a couple ways we can handle this. We can do that same thing before where we make it like the array reference or-- You could do that. Or you can create your own iScope. For example, you can create an ibookreview link scope, an interface, or frankly if you just don't care about that, I would change the Scope to any. 'Cuz you're not actually using any of the Scope functions in this case, you're decorating it with your own properties. And that way you can put the Reader back to being normal. The only thing is that watch. Right, yeah. So in this case, I think any is a good example of a place to use it. Otherwise we'd have to leave the Scope there, we'd have to go create an interface, then we create an interface that's got scope.reader, .reviewdata, .readermodel, .watch ... Let's not go there. It's not getting any value out of it, you know what I mean? It's just being anal for the purpose of being anal. So now we've got a Scope that's any, a function.... do we have any other squigglys anywhere? The function doesn't have a return type. So we'll just make that void. So he's going to be voided. We've got some lambda... Opportunities for lambdas, I like those. And now the data is a parameter, you don't need the parenthesis either. If data is a parameter, we don't need a parenthesis? If it's the only parameter you have, you don't need your parenthesis on that guy. Oh, I did not realize that. If you're going to put type on it though-- Oh, then you need parenthesis? Well go type... What type is it, object? Any. Any looks good. Now you're going to have to wrap it up. Okay. So now you've got something called data that's getting passed in, and it's going to return back to function console.log reviewdata = data. Sweet. And if you didn't have the console.log you could literally just get rid of the curly brace console.log and the last curly brace. You can look over to the right, you're still getting back what you thought you were getting. Gotchya. So you're saying if I got rid of the console.log Scope reviewdata could work like this? Exactly. Yeah, Scope reviewdata, just like before. Yup. Gotchya. And so if you want to keep your console.log you just need the curly braces though, 'cuz otherwise it's not execute both of those. I'm going to keep that in 'cuz that was helpful to debug the scripts for right now. And we've got another lambda down below, we can do that guy. Perfect. So lambdas marked weren't too hard to put together. Nope. So while that's there, want to see if the app is working? Yes. Our directive is still working. It's showing up, that's a good thing. Yup. Alright, there's a couple other options we could do with the directive. Let's go look at the function one more time. So we've got our function inside of our directive, called the "Latest Book Reviews Link". That's pointing to a link function. We could actually make that function be typed if we wanted to as well. So instead of saying function Latest Book Reviews Link function, we could actually do let on that function if we wanted to, we dont have to go here, it's kind of up to you where you want to go, but we could set it up as a variable and then define that link function as a function. Why don't we just do it right above it? Just kind of get an idea. Oh, just do it right above it? Just right below the ngInject. Let's just do a quick let statement. Okay. Do let... just call it link for now. This would be the Latest Book Reviews Link. Make this a type function. Right. And it's a capital "F"' because that's the type in this case. And this would be equal to, and now it's got a parameter list, so this is where your Scope any would go. So would I do function? Nope, you don't need that at all, you just need parenthesis Scope any. So that's your parameter for it. And then do a lambda. And then open-and-closed curly brace. Okay, and you need a semicolon at the end, I think. So what he's saying is you're setting up this function here, you're creating it called Link, and then it's going to be defining a function type, which is going to accept parameters of Scope any. And then what you have in between those curly braces would be all the logic for that-- Would be all this here. Yes. And that's where everything in there would go. And then your link function would actually get referenced there. The reason you've got red... put 'em back, okay you've got it there? Leave that for just a moment. See the return statement? Move that to the bottom of your directive now. Oh, right. Yeah, because it sees that you've already returned him, therefore that let function was no longer valid-- It's not going to execute it. Gotchya. So now you've got to let link unused variable. So if I used it now... Yeah, just leave the first line I think, or comment it out if you want to. So now you've got a link function. And now down here, just call "link". Now link is being used. And now, is that function spelled right? It is. There's some white space between the type. (laughing) That's another thing to turn off, right there. So you've got your function, he's there. And when you compile it on the left, let's take a look... that's not the left, is it? That's the right. Anyway. Left, right, who cares. (laughing) If you look at him, he's got a directive with the link function now. Now see how I did the var link? That's why we had to move all the return and everything else below, because now the link is declared up here, and it's used down below. But now we're actually saying, I mean, I'm not sure we added a lot of value with this, but it's showing you that you can define with let the name of your function, and then you can use it later on inside your code. A few different options. Yup. We're not going to change this, but let's make sure it's working. Let's take a look. But there's one other option I'll show you to look at too.
Directive from a Class
Alright, so we just had a lot of fun with this directive, I'm going to blow your mind. There's yet another way to build the directive. So instead of changing this one around, we went a little off-the-books here and said, Let's just make this guy a function, because quite frankly it was easier to leave him as a function. Right? But we could do a class. So if you could go out the GitHub real quick, I'll show you an example where I created a directive from a class. It's at github.com/johnpapa. Sweet. And then in there, there should be one called Hot Towel Angular Type Script. You're going to have to look for it. Hot Towel Angular Type Script. Yes. That one. So go into the source folder, and then in the client, then the app, then widgets. Those are my directives, and look at the header directive. And zoom in a little bit there. For an old man's eyes. Cool. So notice I did the namespace, but here I use an interface, and the interface is for the Scope. Remember, I talk with the Scope, how we get to find a type? So here I created a Scope type, and then I used that down there on line 24. That way I could do .title, .subtitle, and not worry about all that. And what you did instead was the any, which is perfectly fine. Gotchya. But the real power of this one is on line 16, I used a class, and I said, "Hey, this implements ng.IDirective," just like your function did that. Right, which returns an IDirective, right? Yup. And I have my little inject in there, just to show you that this is where you would do your inject if you inject anything in the constructor of this guy. He doesn't. And then skip him for just a moment. Notice the Scope template are your own restrict properties. Those are the same things you had on your DDO. Now, instead of returning a function, I just use it as properties of the class. They're properties of this class. Now that works perfect, but then when we do line 36, which is directive widget-header, we can't just say, Give the widget-header. We can't just give it the class? No, we have to actually have something that will instantiate that directive. It doesn't work like controllers do. With a controller, we were able to say just point to the name of the class. With a directive, we have to point to the class and then something that will actually create an instance of it. So could you also do new here? Yeah, instead of that we could've done new ht-widget-header parenthesis. Well, how would that work with the dependency injection? Right. That's where it gets a little funky with that. So here, it allows you to define the injecting for the obstructor, your static instance, look into that, and returns that factory method or this instance. Yes. And it's got to be a static instance because you have to be able to talk to it. Because down here, that's just the name of the class. It's not an instance of the class, it's the name of the class.instance. Probably a better name is create instance, I don't know... But it's just another opportunity. This is more class-like. If you look at which code you had on the left still, it's effectively the same thing. You're just using a class instead of functions in functions. You could potentially, I don't know how often you would do this, but extend from base directives potentially? Yeah you could actually make this static instance like a base directive, that it creates a base directive, and then kind of use it for that to get rid of some of the monotony. So that would work.
Conclusion
Compiling the TypeScript Code and Opening in VS Code
So, so far what do you think? We've gone from Angular to Typescript. We kind of had two phases right? We did the environment first where we converted everything over to Use, the typescript compiler, and then we actually converted all the code. How bold are you feeling to see if our typescript compiler works? Oh yeah, let's run the Go commands? The Go commands, yep. Sure. Because, remember we first ran it. It gave us all those errors because we didn't convert everything over yet. Right, so Go Analyze was our winter. Okay. So we had a lot of errors from before, and that is clean now. And it's not having any problems. And if you want to make sure it's actually hitting that, we could also do the TSE compiler. With the TSE-P- -- Client. Client yep, and that'll probably just do it quickly. If we go back into your TSconfig j son, it'll show, we can set the list files to true. And let's make sure it's actually hitting our files, right? Yes. Now that I remember what that setting was. I like that. Sweet, now go over here, run the command again. And now it should tell us here is the file's a hit. It is hitting them. So everything works great. Yeah. Will you do me one last favor? Definitely. I'm a VS code guy. Oh sure. I want to see if you can open the same project in any other editor. Certainly I do have that installed here. Yeah I did make you get it. (laughter) This is the same app. This is the same app. This is the admin controller. Okay. TS. And we have the intellisense here. If you hold the command key down on top of that, it shows you the peak. Great and let's go to the service for a minute. Okay. So inside of here, if we went inside of the services, let's see, like part of our ACTP for example, hover over the IHTP service. It gives you the types, shows you all that, we could actually dive into the definitions. So it's showing you that what we did is not specific to intelliJ. It's, you really could use a web store of intelliJ. Sublime, VS Code, Adam, you pick. Right. Right? So it works pretty good. Yeah, yeah, this wasn't too bad. And we could do it in phases as well. We could, at the start we just-- Right. Named the GS files to TS files. We could use NEs all over the place if we want. Yes we can. And then yeah, working those typings as we needed. Exactly, and now you can power that, as you got a really large project, right? You can convert as you go, and notice how we checked the project along the way to make sure it doesn't still work. So you've got that little litmus test. Now what I probably would recommend is in larger projects, you do commits, right? Getting committed, push this up as you're, when things work, push them. Right, yep. You know. Have some unit tests too to make sure that the-- Unit tests would be good. I mean, we could save that for another day. Definitely. Converting all the unit tests. But I think things are pretty good. Yeah. I hope you had some fun. I did, thank you very much for walking through this. Thanks Chris, appreciate it. Thank you.
Course authors
Christopher Martin
John Papa
Course info
LevelBeginner
Rating
(90)
My rating
Duration2h 8m
Released1 Apr 2016
Share course