What do you want to learn?
Skip to main content
A Practical Start with TypeScript
by Roland Guijt
This course uses a demo-first approach to get you familiar with TypeScript. You will cover all of the main language features of TypeScript by building software for a vending machine serving drinks and candy.
Start CourseBookmarkAdd to Channel
Table of contents
Preparing to Write an Application
Course and Module Introduction
What Is TypeScript?
You are not tied to using a specific editor for TypeScript development. Visual Studio makes sense if you're already using it to develop ASP.NET server-side applications, for example, and the latest version also supports Node.js. It is a full-blown integrated development environment, or IDE. You can do a lot of different projects with it. It is free for small businesses or individuals, and it offers a great developer experience, but the downsides are that it takes a lot of resources, takes a long time to start, and runs on Windows only. If you install Visual Studio, tsc is automatically installed as well. A cross-platform, more lightweight commercial IDE alternative is WebStorm, which is entirely focused on creating web projects. Sublime Text and Atom are editors for all kinds of text out of the box, but can be enhanced to code editors with the right plugins. For the demos in this course, I picked Visual Studio Code, VS Code abbreviated, which is a code editor that is free and open source, fairly lightweight, runs cross-platform, and it supports and recognizes all kinds of code files, including TypeScript out of the box. Let's take a look at how to set up VS Code in the next clip.
Setting up Visual Studio Code
Download and install Visual Studio Code on code.visualstudio.com. On that site there are also instructions how to install it for your operating system. In all cases, it is very easy to do. When you're done installing, create a directory somewhere on your drive that will hold the project. I call the directory vendingmachine. Now start Visual Studio Code by typing code vendingmachine. Were you're not in the command line, you can also just start it and go to File, Open Folder, and browse for the new directory. By the way, I switched the color theme to Light for increased readability of this recording. The default theme is Dark. The Explorer view on the left shows the contents of the directory, which is empty for now. You can switch the Explorer on and off by clicking on the top icon on the left of the screen. The magnifying glass icon lets you search the contents of files in the open folder. The icon below that is for the Git integration. And the final icon is to debug your project in Visual Studio Code. Out of the box, VS Code supports debugging for Node.js applications, but with plugins you can also debug against a particular browser. My experience when doing browser projects is that the debugging in the browser itself is a great experience, which I will show you shortly. So we're not going to use the debug icon in this course. If you want a deeper understanding of all things VS Code, there is a course dedicated to it by John Papa in the Pluralsight library, but you don't need the info to continue watching this course. So let's create a new TypeScript file by hovering over the directory name and clicking the first icon. Let's name it helloworld.ts. You can see VS Code understands that this must be a TypeScript file, and it will provide for syntax highlighting and intelligence automatically. Let's create an empty class again called HelloWorld this time. In the next clip you'll learn how to transpile it in VS Code using a build task.
Configuring a Build Task
To transpile the HelloWorld TypeScript file with tsc within the editor, we have to run a build task. You can run it by pressing Ctrl+Shift+P or Cmd+Shift+P on a Mac, which brings up a Search box with which you can search for VS Code commands. Type in build, and you can see it finds the Run Build Task command. That has the shortcut, Ctrl+Shift+B, which I will use from now on. If I run the task, VS Code reports that no tasks runner is configured yet. Luckily, you can configure it by just clicking on Configure Task Runner. After selecting that, we get a list of possible tasks, and we need a TypeScript task, of course. This creates a tasks.json file in a newly created directory called .vscode. This file defines what should happen if the build task runs. This template provides a task for tsc, but there are many more templates of tasks to work with. The template specifies the command to run is tsc, and this is something that has to be executed in the Shell, meaning the command prompt or terminal window. It is also configured to only send output to the Output pane if there are errors. The Output pane can be toggled by going to View, Toggle Output, or by pressing Ctrl+Shift+U. The next line is the args setting. It lists the command line arguments tsc should receive. Let's just specify helloworld.ts as an argument, so that that file will be transpiled. Finally, a problemMatcher looks at the output the shell command generates that can be reported to VS Code as errors. The $tsc is a problem matcher that conveniently ships with VS Code. At this point, save the file and run the task by pressing Ctrl+Shift+B or Cmd+Shift+B. You can see that the task runs because of the spinner in the lower left corner. The problem matcher will report problems in the Output window, so it's a good thing to keep an eye on that. When it's finished, you can see the .js file is generated. It's ready to be referenced in the HTML app we're going to build. However, I would like a task configuration that is slightly more sophisticated. Let's take a look at that next.
tsconfig.json and tsc Command Line Arguments
Bootstrapping an Application
Referencing Other TypeScript Files
In this module you learned the components of a development environment and how to set them up. You saw how to create the project structure for your application and how to bootstrap and debug it. After watching this module, you should have a good idea of what TypeScript is and how to set it up. In the next module, we'll dive into the syntax of TypeScript.
Understanding the Language Basics
This module is about getting to know the TypeScript language basics. After watching this module, you will have a good understanding of the TypeScript syntax, and you can apply built-in, as well as create custom types. At the end of the module, we will have a working vending machine that is able to accept quarters, and it can get you a can of soda.
Implementing a Class
I added an image directory to the project and put an image of a quarter and an image of a soda can in it by just copying it over to that folder. Now let's create a new file in the ts directory called coin.ts, and create a class called Quarter. The process of remodeling a real-world object, like a quarter into a class is called abstraction in object orientation. Let's give this class a field of the type number and an initial value of 0.25, which can be written just as .25. Semicolons are optional in TypeScript, so it's up to you if you want them behind every line of code or not. There's a naming convention going on here. Most developers write the names of types in Pascal casing, that means every new word in a name starts with a capital, and the names of members, like a field, are written using Camel casing; it starts with a lowercase letter and every new word in the name starts with a capital. Now I add a method called getImageUrl, which accepts no parameter, because there's nothing between the parentheses, and it should return a string in this case. You can also define methods, which don't return anything. In that case, the return type is void. The actual functionality of the method is between curly braces. I just returned a string, which is the relative path to our coin image. There are a couple of things to explain at this point. In the next clip, I'll start with type inference.
Once a field is of a certain type, you can't put a value in it of another type. To demonstrate, I will try to put a string in the field value in the getImageUrl method. Every time you want to refer to something that is on the class level, use the this keyword followed by a dot, and in this case, the field name. When I try to put a string in the value field, you can see VS Code detects an error telling me a string is not assignable to a number. Now let's do something interesting. Let me remove the type declaration of the number field. You can see I'm still getting the same error. Even though I didn't specify it explicitly, TypeScript knows values should be a number, because I assigned a number to it. This is known as type inference. You can apply the same trick to a method. When you leave off the string return type, the return type of the method will still be strongly tied to a string, simply because of the fact that I'm returning one. In the next clip, learn about how to do class encapsulation with TypeScript. Let me try something out here. I create a variable called coin and assign it
Let me try something out here. I create a variable called coin and assign it to a new instance of the Quarter class. Note that this variable has Quarter as its type because of type inference. When I type in the variable name followed by a dot, you can see I can access the value and getImageUrl members of the class. I can also change the value in the value field, but in this case I don't want that. I want a quarter to always have the value .25, and I don't want something outside the class to modify the value. In TypeScript you can control accessibility of members by typing access modifiers in front of them. If you don't do that, like me in this class, the access modifier is public implicitly; that means something outside of the class can read a value and write a value. Let's make the value field private by typing in the private keyword in front of it. Controlling access to a class like that is part of the encapsulation principle in object orientation. As you can see, I can't access value from outside the class, but I can from within the class, but this is not something I want for the Quarter class. I like to be able to read a value, but not modify it outside the class. Let's see how we can do that in the next clip.
To make sure the value field can only be read, we create a property. Properties also support encapsulation in object orientation; they control access to the class. I write the so-called accessor, which can be get or set. In this case I only use get because I want the value to be read-only. Note that the getter is a function called Value with a capital V. It returns the number inside the private field value. So now I have limited access to the value field by using the property. There is no difference in syntax between reading a field and reading a property from outside the class. The compiler will also agree if I put a number in the Value property, even though there is no setter, but the value won't actually be set. Should you want a setter, you can add it in like this. It's a function again, but now it accepts a parameter, which is the value put in the property. You could do some validation of the value first before you put it in the private, if you like. That's in fact the whole point of properties; you can control what goes in and out. Next, we're making a start with the vendingMachine class.
Functions and Arrows
Connecting the UI
So the next step is to create a button in the HTML that will simulate that we're inserting a quarter. I also want the total paid amount on the screen. For styling and positioning, I'm using Bootstrap, but I also want to add some of my own styling in a file called site.css. I add this file to the project and paste in all the styles we're going to need for the demo. I've already added a div that is going to be the container for the UI. Container is a bootstrap class. In the container, I add a div, which will cover two-thirds of the width of the screen, and another one that will take the remaining one-third. In Bootstrap, 100% width is divided into 12 columns. In the right div, taking one-third of the screen, I want the paid functionality. I add a Paid label with a span that is going to contain the actual amount paid. It has the id total so we can easily reference it in TypeScript, which I will do in a moment. Next, I add the button with the Bootstrap classes btn and btn-primary, which has an onclick event calling the acceptCoin function with a new Quarter. Let's switch to the vendingMachine. In the acceptCoin method, I need additional code that updates the span with the id total. I search for the element in the HTML, and I capture that element in a variable. Then I update the innerHTML, which is the text it contains to the new total. Let's run the app and see if it works, and it does, but I'm not very happy with the way this works. I will explain why in the next clip.
Connecting the UI with Knockout.js
Refactoring the UI Logic
Instead of a number, I want the paid property to be a ko.observable with an initial value of 0. This is an object that supports the two-way data binding I was talking about. In the acceptCoin function, I now get rid of the UI logic and define a variable that is called oldTotal, and it captures the current value that is in the observable. You can retrieve the value by just calling the object like a function. Then, I want to give paid a new value. You can do that by, again, calling the observable as a function and just pass in the new value. In this case, the old value added to the coin value. Now switch to the HTML. In the span for the total, I now add a data-bind attribute to set up a binding. This is an attribute Knockout looks for. I say that the text of this element should contain the value of paid. When I now run the app, you can see it works like before, but I now got a much better separation of concerns. I'll talk about the let keyword next.
A vending machine has cells. Each cell has a certain stock of a certain product. For the demo, I don't want each individual product to have a separate image. I want to place the products in categories, so let's add the classes to support this. I'll start with a productCategory class. I first make a new file called productCategory.ts, and add a class to it called SodaCategory, which contains a category name and an image URL. I've already added the image to the img directory. Next, I create a file called product.ts, which for now just contains one product called CocaCola. It has a name, a price, and a category, which is a new instance of SodaCategory. Don't forget to reference the file containing the categories. Then I'm adding a cell class to the vendingMachine TypeScript file. A TypeScript file can contain multiple classes. When instantiating a cell object, the cell should be tied to a product. With a constructor, I can make the passing in of, in this case the product, compulsory while the cell gets instantiated. Since we have only one product for now, I will accept an object of the CocaCola type. Putting public in front of the parameter means that I want to implicitly create a class-level property with the same name for the value that is passed in. The Cell object also has to contain a certain stock of the product, and an indicator that something is sold, which will be used to trigger the CSS animation. Both are Knockout observables. In the next clip we'll take a look at static members in a class.
I want to put the logic to get products in a separate class. Let's create productFactory.ts. It contains a class called productFactory with one static method, GetProduct, which will, for now, just return a new CocaCola instance. In the next module, I will augment the class to return a random product, but you could also create logic to fetch products from a server, for instance. A static is a field, property, or method, in other words a member on the class level. Normal members are meant for the object instances of the class. When you define something as static, it is available on the class level, and it won't be available at the object level. So if I define a static doors property in the house class, you can get to that value by accessing the class and not the object. In the case of productFactory, I want to be able to call GetProduct without having to instantiate an instance of the class. Let's put the productFactory to work in the next clip.
The VendingMachine has to be flexible in terms of number of cells supported. I want to support 6, 9, or 12 cells, or small, medium, and large. I create a new type in the vendingMachine.ts file that supports this in the form of an enum called VendingMachineSize. VendingMachineSize is an enum. By declaring an enum, I'm declaring a new type. So I can declare variables or accept method parameters and type them to the new enum. I will construct a property for the vending machine shortly called size, which will be of the type VendingMachineSize. Instead of assigning the number of cells to it directly, I can tell it to use the medium size, which corresponds to a machine with 9 cells. But what are the benefits of using enums? First, it can act as a constraint. We could type the size property as a number, but in this case I don't want a machine size of 7 or 10; I only want 6, 9, and 12 as options. By creating the enum and making the size property use the enum type, anyone attempting to set it will only have these options. Secondly, it can increase the maintainability of the code. Let's say I want this changed to a number of cells for a certain size. For example, large is becoming 15 instead of 12. Using an enum, I only have to change it in one place, in the enum itself. Lastly, code can become more readable when using enums because of the semantics of enums. Suppose the size property would accept numbers, a size of 6 isn't really semantic, 6 what? Setting the size of medium is more friendly to the user of the class.
Let's add a cells field to the vending machine. It's type is a Knockout observable array. An observable array is the same thing as an observable, it just has methods to add or remove elements from the internal array it uses. The initial array of items is empty. Now I'll implement a size property. I want it to be a write only property, so I can only use the setter from outside the class. It should use the new enum as its type. Even though you assign values to a property using the equal sign, in the background a function is executed with a value on the right side of the equal sign passed in as a parameter, which I call givenSize. First, I'll clear the cell's observable array to make sure it's empty by assigning an empty array to it. Then, I'm constructing a for loop by using the code snippet in Visual Studio Code. Just type for and press Tab. The for loop declares a variable called index and assigns it the value of 0. Let's make the var a let for this one. The next part is an expression. The loop will continue to run until the condition is false, and the final part is what the loop should do after each iteration. In this case, increase the index variable by 1. In the loop, I declare a product variable and asked the productFactory to get a product for it. Remember, I can call the GetProduct method directly on the class without a need to instantiate productFactory, because it's a static method. Next, I add a new cell to the cells array by constructing a new cell, passing in the product by using its constructor. In the bootstrapper code, I set the size of the VendingMachine to medium, and that way the cells array will get filled with 9 cells. Let's go to the HTML. The first two-thirds of the screen will be filled with the cells. I add the CSS class machine to the col-md-8 div and add a data-bind to it. I want its contents to be rendered for each of the cells in the cells array. Each shell should take one-third of the available width, and I add the cell CSS class for styling. Within each shell, an image should be displayed taking up half of the width of the cell. I add a data-bind to the img tag contained in the div. This time it's the attr binding that is data-binding the view model class to the attributes of the tag. I want the src attributes to be bound to the image URL of the category and the alt to the name. The other half of the width is the product info. I want the product name to be displayed there, the stock of the cell, and the price of the product. Now let's run the app. You can see each of the cells are filled with a product, but I still have to add the functionality to pay for an item. Let's do that in the next clip.
Applying Object Orientation
In this module I'm covering some more principles of object orientation. At the end of the module you will see a vending machine operating with more coin types, product categories, and products. First, I'll explain what problem polymorphism solves, so you can recognize it in action. We look at class inheritance, which enable base classes, which can be abstract. And lastly, you'll learn about applying interface types. We will apply all these concepts to the vending machine app. Let's continue to work on our coins in the next clip.
The Problem Polymorphism Solves
Here's the coin.ts file. Let's add another coin class called Dime, which also has a getImageUrl method that returns the path to the Dime image, which I added to the img folder together with the other coin images we're going to use. In the vending machine TypeScript file, I want to add a Dime object to the acceptedCoins array, so that it will display on our HTML page. As you can see, that doesn't work. That's because the elements of the array are tied to Quarter, and a Dime is not a Quarter. The need arises here to have an array of coins in which I can stick all coin objects, such as Quarter and Dime. TypeScript supports this through a concept called polymorphism, which will you see me implement in the next few clips. To apply polymorphism we need inheritance, and that's the topic of the next clip.
I want a common type for all coins, something that defines all common things about a coin to the actual coin, like a Quarter, just has to implement the specifics. So let's create that so-called base class. Now I have to let the Dime and Quarter classes know that they are coins. I can do that by using the extends keyword behind the class name. Everything that is in the coin type will be available in the Dime and Quarter classes, provided it is not declared as a private. There's nothing in it right now, but we'll work on that. This is called inheritance. Coin here is the base class defining everything that is common for all coins. A Quarter and Dime are the derived classes, with inherit everything non-private from the coin. Each class can inherit from just one class, so if you apply multiple levels of inheritance, the class diagram will look like a pyramid. In the next clip, you'll see how this applies to polymorphism.
When I switch to the VendingMachine class again, you can see that the line with the acceptedCoins array now seems to work if I type the array to the Coin class instead of Quarter. It works because Dime and Quarter inherit everything from Coin, and because of that, we can say dimes and quarters are coins. The compiler understands this, so it can type the array to Coins and put a Dime and Quarter in, and when I run the application, it all seems to work because Dime and Quarter have a getImageUrl method, which is called in the HTML. But let's say I forgot to implement the getImageUrl method, then the application goes south. Somehow as I code, I want to make sure each derived class has a getImageUrl method. I'll make that happen in the next clip.
Right now, having the Coin base class doesn't make much sense. It doesn't contain anything. The Coin class isn't meant to be instantiated, it is just meant to add as a base class for the actual implemented coins, like Dime and Quarter. But we do want to make sure derived classes implement the getImageUrl method. You can do this by specifying getImageUrl in the base class and omitting the method body, and marking the method as abstract, and if one member in the class is abstract, the whole class has to be marked as abstract. After doing that, the class can't be instantiated anymore. Now at compile time, the presence of a getImageUrl method is checked in derived classes. It is now compulsory to implement it. The code won't compile without it, so I quickly put it back and have the code working again. Let's move more code to the base class in the next clip.
Since every coin has a value, it makes sense to move that property to the base class, as well. In this case simply because it saves you lines of code, and it increases the maintainability of the code. I also add a constructor accepting the value that stores value in the class. In the constructors of the derived classes, I can now call the constructor in the base class with the correct value. You can call the version of a constructor in the base class by using the super keyword. So by using the super keyword, you can call the base class constructor, but there's another way to use the super keyword. Let's say we have a class called Base with a method called baseMethod, and a class derived from base with the same method. By using the super keyword in the Derived class, I can call also the method with the same name in the base class. Of course, you could also pass in parameters, if needed. Because you decide on the moment you are calling the baseMethod, you can do stuff before and after the baseMethod runs. To make the code even shorter, you can omit the declaration of value in the base class, and just put an access modifier in front of the constructor parameter. TypeScript will implicitly create a property for value. Let me introduce you to a new access modifier in the next clip.
I already talked about the private access modifier, which hides members of a class for everything but the class itself. A public keyword also exists, which opens up members to other classes; it is a default access modifier. But there's another one. Protected works like private; members are available for the class itself. In addition to that, protected members are also accessible in classes that derive from the class. In this example, there's a field called num and a class called Base with the protected keyword in front of it. When I derive a class from Base, num is accessible, but when I instantiate a Derived class in an unrelated class, for example, num is not visible. Using protected just like using private is useful for encapsulation. It helps you hide complexity in classes without losing the ability for derived classes to access these members. Hiding complexity helps you to write more maintainable code, so I recommend to hide as much of a class as possible. You keep the coupling between classes low that way, and when changing the code there is little chance that other parts of the code break. In the next clip, you'll see how protected works in our advantage for the vending machine.
Using Protected Members
Now let's create two more coins, a half and a dollar, and add them to the acceptedCoins array in the vending machine. For productCategory I create a base class with a protected string containing the imgPath string and name field, and an abstract getImageUrl method. SodaCategory just fills this name property with a value and implements the getImageUrl method, which is now compulsory. Because the path string is protected now, derived classes can easily use it while at the same time I hide the field from everything not deriving from the ProductCategory base class. Now I have that in place, it's easy to create a lot of other categories, and, of course, I added the appropriate images to the img directory. Let me show you how to use interfaces in the next clip.
Interfaces are cell-defined types just like classes. They can't contain any implementation. They act as a contract for a class. Everything defined in an interface must be implemented by the class implementing the interface. A class can only inherit from one class, but it can implement multiple interfaces. The difference between an abstract class containing only abstract members and an interface is that an interface isn't bound to a certain class tree. Unrelated classes can implement an interface. Let's quickly make this more concrete. I create an interface called Product containing a name, price, and category property. Every class that implements this interface must contain everything that is in the interface, so in this case a name and a price property. There is an exception to the rule; if you specify a member with a ?, the presence of that member is optional. Now I apply the interface on the CocaCola class. Implementing the interface on the CocaCola class will just work, because it already contains all the members specified in the interface. When I create another class called Initial, which I will use as the product that is selected when the application is started and let it implement the interface, Visual Studio Code detects that not all necessary members are present, and it's only satisfied when I add them. You can see I can omit the category. Now let me paste in some other products that all implement the interface. Now let's refactor the product factory. Polymorphism also works with interfaces, so I can let GetProduct return an object of a class that implements the product interface. Next, I calculate a random number and depending on what the number is, I return a specific product. In the constructor for the Cell class, I also change the constructor parameter to be of type Product. Now let's change the initial product in the vending machine from CocaCola to our special Initial product and run the app. Great, we have a fully functional vending machine now.
In this module you learned how inheritance and polymorphism work together and how abstract classes form ideal base classes. The super keyword plays an important role in inheritance to call into the base class, and interfaces are a great way to use polymorphism with unrelated classes. In the next module, we're going to see how to optimize the code using additional code structure options and generics.
You're watching the fourth module of the Getting Started with TypeScript course. Here's what I'm going to talk about; the global namespace isn't really a feature of TypeScript, but it's important to understand how it works. You'll see how to group your code when an application gets larger with namespaces and modules. The TypeScript language feature called Generics can save you many lines of code. And finally, something that's experimental in TypeScript for now, but important to understand if you're going to work with TypeScript in combination with Angular 2: Decorators. The global namespace is up next.
The Global Namespace
Every time you declare a class in TypeScript, it is added to something called the global namespace, which is like an application-wide bucket of classes. The thing that identifies the class is a name. In an application, we declare a lot of classes, and there are no problems as long as every name is unique, but what happens if a class is added that is different but has the same name? Then the class that came in first is overwritten, and isn't available anymore. This not only goes for classes, but for everything you declare inside a global namespace. You're okay if are to declare something that is contained in another structure, like a function or a class, but all classes we've declared so far in the vending machine are in the global namespace. This isn't much of a problem in the case of our vending machine demo, because it is a small application with a limited set of classes, but when the application gets bigger and multiple persons are writing TypeScript for it, this can lead to hard-to-find bugs. When the amount of classes increases, you might want to group them using containers named in a smart way. By putting classes in some kind of container, only the name of the container itself will be exposed to the global namespace, so there's less chance of naming conflicts. From a logical point of view, this might also be a good idea. Accessing a class via its container might add some needed semantics. For example, our Quarter class could be contained in something called Coins, and then you would access Quarter by using coins.quarter. Finally, these containers add an extra layer of encapsulation. Classes within the container can either be exposed to the world outside the container, or only be accessible from within it. There are two types of these containers in TypeScript, namespaces and modules. In the next clip, you'll see namespaces in action.
Let's imagine we're in the business of creating a collection class for strings called StringCollection. It has an add method to add strings to the collection, which accepts only strings. And there will be more methods in the class working with strings; for example, to retrieve values from the collection. I'm perfectly happy with the class, but sometime later, I need the same class for numbers, so I have to add a class to my project, which is essentially the same. The only thing that is different is the type of the items it works with, and it might also become handy to have a collection class for quarters, as well, for which I have to add another class with the same structure. Generics can save you a lot of lines of code in this scenario. This is a generic class. Generic classes accept a type parameter, in this case called T, because it has T as a type parameter, it is called Collection of T. You're not tied to using T as a types parameter, but it's convention to call it T if you just have one. So T is a type, which is unknown at the time you create a class, but you can use it everywhere you want in the class. Here I'm using it to type the parameter of the add method. The type T has to be known as soon as you create an instance of the class. At that time, you fill in the type. You can see that I'm creating a collection of string here. What effectively happens is that TypeScript will create a new class in the background substituting T with string. The class isn't anywhere in your TypeScript code, but it will be present in the transpiled code. Using the same generic class, I can now create all kinds of collection classes reusing the code I wrote in a generic class over and over again. Generics are not only for classes. You can create generic interfaces and functions, as well. In the next clip, you'll see generics applied to the vending machine.
Let's take another look at the Cell class. When I hover over ko.observable, you can see that we, in fact, already used generics without knowing it. Ko.observable is generic. Stock is a ko.observable of number, and sold is a ko.observable of Boolean, but I didn't specify a generic parameter. This is, again, type inference at work. Because I assigned 3 to stock, TypeScript infers that it has to use a number as the type parameter, and I assign false to the sold observable, which is inferred as a Boolean. You can of course also be explicit if you want, by adding the generic type parameter. Also, take a look at our acceptedCoins array. It's tied to Coin, so only types that derive from Coin can be in the array. This is in fact just one way to define an array in TypeScript. You can also use the generic class, Array, to create an array of Coin to achieve the same using other syntax. In the next clip, we'll level up with generic constraints.
The collection class is a good demonstration showing the power of generics, but what if you want to call functions on your T object inside the generic class, or access fields or properties? In this example, you'll see what I mean. Now I have a CoinCollection of T class, which has a function to add an item. The item is taught in a private array, and it has another function to get the total money value of all coins in a collection. Incidentally, you see another way of doing loops in TypeScript here. The forEach method accepts a function that gets executed for each item in the collection, it's ideal to use an arrow function here that adds the face value of the coin to the total variable. Well this code doesn't work. Why? Because TypeScript doesn't know what type T is. TypeScript is a typed language, and it won't allow you to read the value property because T could be anything. To solve this, you can add a generic constraint to the class. Here I state that T must be a descendant of Coin, and then Coin, the value property is present, so I'm allowed to use it. Of course, TypeScript won't accept a type for T now if it doesn't derive from Coin. You'll experience the real power of generics if you start deriving from generic classes or use generic interfaces. Here you see a new class, QuarterCollection, which derives from CoinCollection of Quarter. Now everything that is common for all coins can be in the base class CoinCollection, and in QuarterCollection I can implement specifics for quarters. Let's look at decorators in the next clip.
Decorators are an experimental language feature in TypeScript, so the way they work might change in a future release. The reason to add the topic to the course is that Angular 2 uses them. Angular 2's preferred language is now TypeScript, and maybe you're watching this because you want to use TypeScript with Angular 2. Decorators are functions, but a special kind of them; you will see that shortly. Decorators can be used on classes, but also on methods, properties, and parameters, and the best part is that you can write a decorator once and use it on as many classes as you like. Because decorators are experimental, you must explicitly enable them in tsconfig.json first. This is a simplified example of using the component decorator in Angular 2. HomePageComponent is a normal class with a name property, and it has a Component decorator above it. Because the Component decorator is above the class, it works with that class. Here it's defining a view for the HomePageComponent class, which data binds to the name property of the class. The Component decorator itself is a function, in this case in the Angular framework, but you can write decorators yourself, as well. The function takes the object involved, the instance of the class it's above, and a configuration object as a parameter. It uses that information to do something with the object passed in. In this case, create a view for it, but it could be anything, in fact. It's possible to use decorators to do interception of classes, add extra functionality to them, and even change them.
To summarize, exposing anything to the global namespace can't be avoided, but do it as less as possible as a best practice. Namespaces and modules help with that, if you're creating larger applications. Generics can help you to reduce your code base, and decorators are there to add reusable functionality to your methods, classes, properties, or parameters. Thank you for watching this course. I hope you have a blast with programming in TypeScript.
Roland is a Microsoft MVP enjoying a constant curiosity around new techniques in software development. His focus is on all things .Net and browser technologies.
Released18 Jul 2016