What do you want to learn?
Skip to main content
by John Papa and Dan Wahlin
Resume CourseBookmarkAdd to Channel
Table of contents
Getting Started with TypeScript
Why use TypeScript?
TypeScript Syntax, Keywords, and Code Hierarchy
Tooling and Framework Options
Tooling and Framework Options - TypeScript Playground
Tooling and Framework Options - Visual Studio
Tooling and Framework Options - Web Essentials
Tooling and Framework Options - Sublime Text
Tooling and Framework Options - TypeScript Compiler
Tooling and Framework Options - NodeJS
Hello World Example
We've hit that magic moment when we get to do a hello world example. So what I'm going to do in the demo that follows is walk you through some extreme fundamentals, just to break you in. We're going to go ahead and use Visual Studio for this particular demo, but we could use any of the other editors that we talked about, as well. And just walk through some of the core fundamentals that we'll be covering later throughout this course. So let's jump in.
Hello World Example - Creating a Class
Typing, Variables, and Functions
Grammar, Declarations, and Annotations
Static and Dynamic Typing
Compile Time or Run Time
Ambient Declarations and Type Definition Files
The Any Type and Primitives
Arrow Functions and Debugging
Functions and Interfaces
Now let's create a couple more functions and see how we can use interfaces to really clean them up. So let's go and create a new file and we'll call this "2-8-interfaces" and let's make a little bit of room so we can have more room to type. And first, let's create a function without any interface; we'll just create one called "squareItBasic." And we want this to be a function that accepts a number and then it's going to return number times a number. So whatever you pass in it's going to multiply it and return it out. Notice in the definition it's using type inference to figure out the return value is a number, but I didn't tell it what the parameter was coming in. If I did that, I could simply do number right there. Now, you can see it accepts a number and returns a number. Pretty easy to do. Now, what if I wanted to make sure I could reuse this and make sure it follows a certain pattern? So I could create an interface and I could call this the "SquareFunction," and let's go ahead and define this as having some value, being passed in which is a number and then asked to return a number. So we're saying this is an interface and we're going to accept a parameter called x, which will have a number, and that it will return a number. So let's get rid of the number parameter down there and all we have to do to make sure this guy here follows that interface is just say, "All right, let's set squareItBasic to use these SquareFunction interface and it will tell us right away if we're okay." For example, if I did something that was out of the ordinary, like let's say I passed another variable like "foo," then it's going to tell me right off the bat that, "Look, you're not following the interface. You can't convert this one to that one because it's expecting different parameters." So we can get rid of that foo parameter. And that's a very, very simple interface. Let's go and take a look at how we can fix up the rectangle example we did in the previous sample using interfaces. Now, let's go fix up the rectangle sample we did in "2-7 functions," and I'm going to go open up the folder or the code that we already wrote, and then I'm going to grab all the code for the squareIt starting here at line 19 all the way down to the bottom where I could write them out in the console. So we're going to ahead and copy those over and I've got squareIt right here. Remember all this code that we wrote to say, "Here's a rectangle. That's going to be the parameter that we pass in with the height and the width or the width is optional and it's going to return a number. Wouldn't it be nice if we could run an interface to do this?" So here we can take an interface for the rectangle and we're simply going to define the rectangle interface to have h and w. And in the interface we can define optional parameters, too. So we've got an optional property here for w and h is mandatory. So what we could do here is now say, "All right. We're going to have rectangle right there, it's a new parameter, and it's going to be of type rectangle interface and it's going to return a number. Much cleaner, isn't it? So now we've got this code instead of saying, "All right. We could put the full code up here," instead of saying, "Down here, we have squareIt with all that code." So it's just a little bit cleaner and it's much more reusable, so you'd be using this interface in this case. But let's go ahead and take a look at another example which allows us to combine several of the learnings that we had so far. Let's create an interface called "Person" and we're going to give this a couple of properties. So far, I've given it a name and age and kids properties and I've also given a property for calculating the pets. So now, we've got our person interface right here, and we can define an object based upon this person if we want to. So we can define p down here and we can create him and say, "Look, he's got to follow this person model," and then when I do p. you're going to see those properties popping up here. If I do calcPets, you're going to notice it's going to have a return value of a number. If I do age on here, then we can set that equal to nine, or whatever else you want to do. If I try to set it to a string, it's going to tell me, "Look, that's not the right person that we have." So, what can we do with this kind of an interface? Well, let's map it out a little bit further first. Everybody wants a function called "makeMeYounger," so let's go ahead and create a "years" parameter so when you pass in the years, I'm going to make you that many years younger (chuckle) than you were. Now, we're going to take the void on this case, so we're going to make you younger. So if you pass in seven, I'll make you seven years younger, but it's not going to return anything. And let's have a greeting on here. Every person needs to be very friendly, so we'll have a greeting that we can pass in, and when we do that we get back a full greeting which will include their name. So now we've got different properties on the person interface; we have name, age and kids, and one of them is optional. And then we have a function for calculating pets which returns a value, makeYounger returns nothing, it's going to operate on the age internally, and then greeting is going to use the name property and then output a string. Now we can take the person and we can implement it and we simply do that by creating an object literal, and inside here, now it's red because it's not actually implementing the interface yet; we're missing all sorts of properties. We can say the name is going to be, let's make it "Colleen," and I can set the calculation of pets to be a function (typing) and we're going to say, "How many kids do you have?" (chuckle); we can do this kids times two, that's how many pets you're going to have. So every kid gets two of them. And notice here I try implement, the full interface for a person using the same format and structure that the interface has up here, all the red lines go away. If I change one of these, like let's say I made the message for the string be something different like a number, we're going to validate the interface that we have, so it's going to say, "Look, you know, it's incompatible in this case." Or we could add an additional parameter to this. If I add another parameter here called "foo" and I made it of type any, it's going to tell so we don't have that same interface implemented. We have to implement the interface for Person up here. Now, we can add other features in here, too, so we could add another property like "favoriteMovie." And notice we didn't invalidate the interface. We still did the minimum interface of what the properties are up here, so favoriteMovie, "Lord of the Rings," not a problem. So if we want to, now, we can examine this p object. We could use something like create the "pets" variable and we could do p.calcPets and we can pass in nothing to pets because that's what it expects, and then we can console log it. And let's go ahead and make myself a little bit younger here -- actually, make "Colleen" younger. We'll be nice, we'll take 15 years off her. And now we're going to say, "Go ahead and get the new age." We'll get a new property called "newAge," and let's also go ahead and print out a greeting. So notice now we can use all the different methods and properties that we have inside of our Person object. calcPets gives me the IntelliSense to tell me that there's no parameters coming in and it's going to return a number, so I can then perform operations on it. I could say, you know, the pets times 9 if I want to, or plus 8. Can't pass in parameters to those because those parameters wouldn't -- it would invalidate the signature of the function up here and then only -- then I have to change the value up here so I could post in num here and make it number, which should then make this code right but then this code is wrong because it's no longer following the interface that I have up top. So I have to get rid of that, and once I find the interface is working, I can get my code back again. Now, makeYounger is going to pass in 15 for the years and then it's going to take that and it's going to reduce the age. And notice the context that we have for this function. We have this keyword and that this keyword is going to represent the p object. So therefore on that object, I can go ahead and use the h property which will be for the person. So it's going to reduce that and it should print out 25. So we're expecting here for our pets to be 8 because we have 4 kids times 2 pets, and then when we make makeYounger it's going to change the age from 40 to 25, so I should put that into console; and then which should say, "Good day to you" and then the name of the person, "Colleen." Let's take a look. We'll go ahead and run this by clicking on two interfaces and we'll view it in a browser. And notice we have here, our values to the squareIt, then we have our 8 pets. We have our 25 for Colleen and then we have a message printed at the bottom. Very simple to do. And you can still set breakpoints inside of here very easily, notice I set a breakpoint there. Again, I can go up to Tools, Options, go down to Web Essentials, TypeScript, set the source map to true and that's going to automatically generate the source map file for us, and that actually sets the source map flag on the compiler. And once I do that, and I save, if you look over on the right-hand side, you're going to see the interface's js map file which is going to be used to help debug it. So now, when I click on browsing and I go into the basic interfaces, I jump right inside of the function. And notice I can see the IntelliSense for the value for kids even though kids is not in the function, it's out here on the object called p. So what have we seen here? We've seen quite a few examples on how we can set up functions and use things like void or the return types, or the arrow functions to really clean up our code, and we also saw how we can create an interface to define what our objects look like as in the case down here with the person. But we can also use an interface to define what we return from an object as well. So to save us some time on this one, let's go ahead and flip over to our "Before" folder in the code and right where you see After and Before, you'll see "returning-interface" text file and inside of there you'll see some text. Well, let's go ahead and grab that text and let's go back to our code and let's paste it in at the bottom of the module right above the curly braces here. Now, let's take a close look at this first and we'll minimize the function. So first thing we did is we created an interface called "SessionEval," and this interface is defining a function called "addRating" which will accept a number and then return nothing. We're just going to add ratings to it. And then we've got a function called "calcRating" which is a function that's going to return a number and has no parameters. The purpose of this interface is we're going to find an object that we can use to calculate session evaluations. So as you're scoring the sessions on a score to 1 through 5, it's going to push it into an array and then when you call calcRating, it's going to tell you the number -- sounds pretty simple. So we defined our function now and the function is defined using this SessionEval interface, and then internally we've got over our logic here for how we're going to implement addRating and calcRating and then the key is the return statement. What we've done is we've said, "Okay. We're going to define this sessionEvaluator. It's going to implement SessionEval. It's got to have an addRating method and it's going to call this internal addRating and it's got a calcRating method, which is going to call the internal version. So this one is going to match up with that right there. And then, we can simply just say, "Go ahead and create s," because that's going to equal the execution of sessionEvaluator, and the reason I'm executing that is because by executing it I'm getting the return object and that return object is represented by the interface that we created, this SessionEval. So down here, we've got s which is actually of type SessionEval, and then I can push a bunch of ratings in and then I can calculate it out and print to the console window. Let's take a look at what this does when I view it in the browser. Notice it calculated the rating of 4.75. So this shows how we can use an interface as the return type of an object, and then the previous example we saw how we can use an interface to define what the object itself would have for its properties. The interfaces that we've seen so far have been pretty powerful at cleaning up our code, but in the next module, Dan is going to show you some even cooler ways that you could use interfaces when you're creating things like classes.
Static Typing Recap
Classes and Interfaces
In this module, we'll take a look at how classes and interfaces fit in to the overall TypeScript language. I'll start off by defining what classes are and how they can be defined within your TypeScript code, and then we'll look at different members that you can add inside of classes. From there, we're going to look at interfaces, define what they are, and explain how they can be used to provide consistency in our code and how they can be integrated into classes. So let's go ahead and get started by talking about what classes are and how they can be defined within TypeScript applications.
Demo: Defining Classes
Demo: Property Limitations
Casting and Type Definition Files
Demo: Casting and Type Definition Files
Demo: Extending Types
If you've ever had a set of objects that needed to implement similar behavior across the objects, such as they all have a start and a stop function, then one way you could ensure the consistency is to use interfaces. Interfaces are code contracts, and we'll talk about what that means a little bit more here if you're new to interfaces. One of the nice things about TypeScript is it provides excellent support for interfaces, which is very useful in a variety of scenarios. So let's jump in and first talk about what are interfaces. So an interface is really just a code contract, but if you haven't ever worked with interfaces before that may not make a lot of sense. So let's do an analogy to a factory. Let's say we have a factory that produces engines, and these engines are physical engines, you can look at them, and on each engine there's a green start button and a red stop button. So any engine you're given outside of this factory will always be started by pressing the green start and stopped by pressing the red stop. And I think you'd agree, that's a very consistent visual interface. Now, what's nice about that is if a new engine comes out, I don't have to retrain the people that start and stop the engines; they just can push the same buttons even if it does something totally different than what they're used to with a given engine. Now, instead of thinking these as visual engines, as you can see with the square or the rectangle and the triangle and things, think about these as being classes. So we have Engine 2 as a class and Engine 1 as a class, and Engine 3 as a class, and they all need to have a start function and a stop function. Well how do we enforce consistency across all of those classes? And the answer is, of course, we use interfaces. Interfaces provide code contract. So we can define an interface that has start and stop, and then these three classes can then implement that interface. Now if they forget to put the stop, as an example, then it's not going to work right and the TypeScript compiler is going to fail, and that's what interfaces buy you, is they provide consistency and if the class doesn't live up to the code contract and do exactly what it says, then it's not going to compile properly. Let's take a look at how we can now define and interface, then. So an interface is defined by using the TypeScript key word called interface. So if you've worked with other languages that use interfaces this won't really be a surprise to you because it's very common key word, but this is what we'd be using in TypeScript. So in this example we're defining a code contract by making an interface called IEngine. Now in this example IEngine has two members inside of it and those members are called start and stop. Now these are the two functions we want any class that implements this interface to have. This will provide our consistency across our classes. So in this example we have the start and stop, they both take a callback. Now the callback, which we saw in the previous section of this module, really is just a callback function, it's not primitive like a number string or a boolean, and you can see that the callback function must take a bool and a string as a parameter and its void; it doesn't return anything. And then start itself is void. And then stop itself is also void. So this is the return type of start and stop. This right here, the void here, represents what's returned out. So here's an example that kind of breaks down what I just said. So we have an interface called IEngine. It has a start function which takes a callback function as a parameter. So the start accepts callback as the parameter, but callback is not a primitive like a string, a number or a bool; instead it's a callback function. And you'll notice that start itself doesn't return anything at all. But callback must have two parameters, bool and string, and it doesn't return anything either; it's void. And that's exactly what we're doing with the callback here. Now, I can define more primitive functions as well if I'd like, just normal like a stark with a string and a string, as an example, and I can even define fields. So let's look at how we would do fields. So here's another interface called IAutoOptions. Now this one only accepts fields, as you can see, but we could certainly add functions as well, if you'd like. Now there's three of them that are required, engine, basePrice, and state, but with TypeScript you can actually make the variables optional. So make, model, and year in this case are optional type of parameters. And what that does for us is, now, anyone that implements this interface, has to have engine, base price, and state, but make, model and year are something they can exclude if they'd like. So it gives us a little bit more flexibility. Now, what do you do with the interface? Well, once you've defined an interface, a class needs to implement that contract, and the compiler will enforce the contract and make sure that you implement all the members of the interface. So the way we do that is we use the implements keyword in TypeScript. In this example we have a class called engine, it implements IEngine, and we know that IEngine has start and stop. Well, that of course means this class must have start and stop, and the signature of the return and the parameters must match up. In this case we have our little callback scenario that we saw earlier. Now you'll notice here that I didn't explicitly put call and void. I certainly could go in and do that. Now, once you have an interface defined, you don't have to implement it. You can also just use it somewhere in a class. So here's an example where engine is defined as a field but we're saying, you can pass me anything that implements IEngine. Now this leads to polymorphic behavior. In other words, we have a set of engines, all implement start and stop, but the way they start and stop may be different and that give us polymorphic behavior. We also have in the constructor the ability here to pass in some data object that implements the IAutoOptions, and that had the make, model, year, and things like that I just showed you. Then we're simply going to assign those up into our fields. So those are examples of how we can use interfaces not only just on classes, like we did with the engine, but also in classes. And it allows for flexibility, so I don't hard code the type of engine to use here or the type of AutoOptions to pass. I instead say, I can assign any engine that implements IEngine interface and I can pass any data object that implements the IAutoOptions. So, now you've seen how interfaces work. Let's take a look at an example of using them.
Demo: Using Interfaces
Extending an Interface
Demo: Extending an Interface
Identifying a Module
Creating an Internal Module
Internal Module Accessibility and IIFE
Extending Modules and Importing Shortcuts
Organizing Internal Modules
Separating Internal Modules
External Modules and Dependency Resolution
Importing External Modules Using AMD
Importing 3rd Party Libraries Using AMD
If you want to use things like jQuery or other external libraries inside of TypeScript when using AMD, you can do that. Let's take a look at the sample in the TypeScript AMD folder under amd-jquery. And then we can look at the different files, the same ones we had in the AMD demo. Here, let's take a quick look first at dataservice, we didn't changed anything in here, it's just going to get us back this welcome message. Then let's take a look at the alerter. The alerter did change a little. Instead of using the alert message, we're actually using jQuery and then we're also going to use toastr, another third party tool to print out the message. So we're going to put a message on the screen and we're also going to pop it up with the toast. So, how do we do this? Well, those guys don't have modules created in TypeScript, so a couple ways we can do this. One, we could write those modules ourselves and then import them. Or we can just pull in these two libraries right here using the reference and we pull this out of typings and then we can declare the taostr and jQuery using the types that are on those files. JQuery returns jQueryStatic, and toastr returns a toastr. So in those cases, we can just call them, very nice and easy, and we get all of our syntax checking. And it's still going to define the AMD for us. Now because we're not using the import for the module, it's not going to load toastr jQuery when it needs to. There's a couple of ways we could define that. Notice over here, it's just saying that requires dataservice. If we pull those in to the main in advance, we could take care of that. So, one way to do this is to preload jQuery and toastr. What we're doing here in the config is we added the shim. So we're saying shim up jQuery and export to the goal NameSpace, this dollar sign. So we have it accessible. And then, we also have the paths here where we're saying, when I top a jQuery, I want you to go look in the path, that's called jquery-1.8.3, that's the version we're getting, it's going to go down the path and grab the Java Script file. And the same thing for toastr, go grab that version of toastr. So this is going to preload bootstrapper, jQuery and toastr even though we're just using bootstrapper in this case. So now when we run this, we're going to have those three guys load up and then it's going to load off to the bootstrapper, which we can open him. The bootstrapper is going to call the alerter and then the alerter is going to call the dataservice and it's going to use jQuery and toaster. So we right-click on AMD jQuery, you can view it right in the browser and you can see the toast in the upper head corner calling toastr. We can all see jQuery printed this off to the screen for us. And if we look down at the sources, we can see that we had jQuery and toastr are both loaded up with require as well as all the other dependencies that we have.
Updated25 Mar 2016