Chapter Summary
Problem | Solution | Listing |
|---|---|---|
Create an object by specifying properties and values | Use the new keyword or use an object literal | 1–3 |
Create an object using a template | Define a class | 4, 5 |
Inherit behavior from another class | Use the extends keyword | 6 |
Package JavaScript features together | Create a JavaScript module | 7 |
Declare a dependency on a module | Use the import keyword | 8–12 |
Declare the types used by properties, parameters, and variables | Use TypeScript type annotations | 13–18 |
Specify multiple types | Use union types | 19–21 |
Create ad hoc groups of types | Use tuples | 22 |
Group values together by key | Use indexable types | 23 |
Control access to the methods and properties in a class | Use the access control modifiers | 24 |
Preparing the Example Project
Working with Objects
There are several ways to create objects in JavaScript. Listing 6-1 gives a simple example to get started.
Note
Some of the examples in this chapter cause the TypeScript compiler to report errors. The examples still work, and you can ignore these messages, which arise because TypeScript provides some extra features that I don’t describe until later in this chapter.
Creating an Object in the main.ts File in the src Folder
Using Object Literals
Using the Object Literal Format in the main.ts File in the src Folder
Using Functions as Methods
Adding Methods to an Object in the main.ts File in the src Folder
Defining Classes
Defining a Class in the main.ts File in the src Folder
JavaScript classes will be familiar if you have used another mainstream language such as Java or C#. The class keyword is used to declare a class, followed by the name of the class, which is MyClass in this case.
The constructor function is invoked when a new object is created using the class, and it provides an opportunity to receive data values and do any initial setup that the class requires. In the example, the constructor defines name and weather parameters that are used to create variables with the same names. Variables defined like this are known as properties.
Classes can have methods, which defined as functions, albeit without needing to use the function keyword. There is one method in the example, called printMessages, and it uses the values of the name and weather properties to write messages to the browser’s JavaScript console.
Tip
Classes can also have static methods, denoted by the static keyword. Static methods belong to the class rather than the objects they create. I have included an example of a static method in Listing 6-14.
JavaScript Classes vs Prototypes
Angular development is easier when using classes, which is the approach that I have taken throughout this book. A lot of the features introduced in ES6 are classified as syntactic sugar, which means they make aspects of JavaScript easier to understand and use. The term syntactic sugar may seem pejorative, but JavaScript has some odd quirks, and many of these features help developers avoid common pitfalls.
Defining Class Getter and Setter Properties
Using Getters and Setters in the main.ts File in the src Folder
Using Class Inheritance
Using Class Inheritance in the main.ts File in the src Folder
Working with JavaScript Modules
JavaScript modules are used to manage the dependencies in a web application, which means you don’t need to manage a large set of individual code files to ensure that the browser downloads all the code for the application. Instead, during the compilation process, all of the JavaScript files that the application requires are combined into a larger file, known as a bundle, and it is this that is downloaded by the browser.
Note
Older versions of Angular relied on a module loader, which would send separate HTTP requests for the JavaScript files required by an application. Changes to the development tools have simplified this process and switch to using bundles created during the build process.
Creating and Using Modules
The Contents of the NameAndWeather.ts File in the src/modules Folder
The classes, functions, and variables defined in a JavaScript or TypeScript file can be accessed only within that file by default. The export keyword is used to make features accessible outside of the file so that they can be used by other parts of the application. In the example, I have applied the export keyword to the Name and WeatherLocation classes, which means they are available to be used outside of the module.
Tip
I have defined two classes in the NameAndWeather.ts file, which has the effect of creating a module that contains two classes. The convention in Angular applications is to put each class into its own file, which means that each class is defined in its own module and that you will see the export keyword is the listings throughout this book.
Importing Specific Types in the main.ts File in the src Folder
This is the way that I use the import keyword in most of the examples in this book. The keyword is followed by curly braces that contain a comma-separated list of the features that the code in the current files depends on, followed by the from keyword, followed by the module name. In this case, I have imported the Name and WeatherLocation classes from the NameAndWeather module in the modules folder. Notice that the file extension is not included when specifying the module.
Notice that I didn’t have to include the NaneAndWeather.ts file in a list of files to be sent to the browser. Just using the import keyword is enough to declare the dependency and ensure that the code required by the application is included in the JavaScript file sent to the browser.
(You will see errors warning you that properties have not been defined. Ignore those warnings for the moment; I explain how they are resolved later in the chapter.)
Understanding Module Resolution
The module in this import statement doesn’t start with ./, and the build tools resolve the dependency by looking for a package in the node_modules folder. In this case, the dependency is on a feature provided by the @angular/core package, which is added to the project when it is created by the ng new command.
Renaming Imports
The Contents of the DuplicateName.ts File in the src/modules Folder
Using a Module Alias in the main.ts File in the src Folder
Importing All of the Types in a Module
Importing a Module as an Object in the main.ts File in the src Folder
The import statement in this example imports the contents of the NameAndWeather module and creates an object called NameAndWeatherLocation. This object has Name and Weather properties that correspond to the classes defined in the module. This example produces the same output as Listing 6-10.
Useful TypeScript Features
TypeScript is a superset of JavaScript, providing language features that build on those that are provided by the JavaScript specification. In the sections that follow, I demonstrate the most useful TypeScript features for Angular development, many of which I have used in the examples in this book.
Tip
TypeScript supports more features than I describe in this chapter. I introduce some additional features as I use them in later chapters, but for a full reference, see the TypeScript home page at www.typescriptlang.org.
Using Type Annotations
The headline TypeScript feature is support for type annotations, which can help reduce common JavaScript errors by applying type checking when the code is compiled, in a way that is reminiscent of languages like C# or Java. If you have struggled to come to terms with the JavaScript type system (or didn’t even realize that there was one), then type annotations can go a long way to preventing the most common errors. (On the other hand, if you like the freedom of regular JavaScript types, you may find TypeScript type annotations restrictive and annoying.)
The Contents of the tempConverter.ts in the src Folder
The TempConverter class contains a simple static method called convertFtoC that accepts a temperature value expressed in degrees Fahrenheit and returns the same temperature expressed in degrees Celsius.
There are assumptions in this code that are not explicit. The convertFtoC method expects to receive a number value, on which the toPrecision method is called to set the number of floating-point digits. The method returns a string, although that is difficult to tell without inspecting the code carefully (the result of the toFixed method is a string).
Using the Wrong Type in the main.ts File in the src Folder
Adding Type Annotations in the tempConverter.ts File in the src Folder
Using a Number Argument in the main.ts File in the src Folder
Type Annotating Properties and Variables
Adding Annotations in the NameAndWeather.ts File in the src/modules Folder
Properties are declared with a type annotation, following the same pattern as for parameter and result annotations. The changes in Listing 6-17 resolve the remaining errors reported by the TypeScript compiler, which was complaining because it didn’t know what the types were for the properties created in the constructors.
Using Parameters in the NameAndWeather.ts File in the src/modules Folder
The keyword private is an example of an access control modifier, which I describe in the “Using Access Modifiers” section. Applying the keyword to the constructor parameter has the effect of automatically defining the class property and assigning it the parameter value. The code in Listing 6-17 is a more concise version of Listing 6-16.
Specifying Multiple Types or Any Type
Accepting Multiple Values in the tempConverter.ts File in the src Folder
Using the as Keyword in the tempConverter.ts File in the src Folder
An alternative to specifying a union type is to use the any keyword, which allows any type to be assigned to a variable, used as an argument, or returned from a method. Listing 6-20 replaces the union type in the convertFtoC method with the any keyword.
Tip
The TypeScript compiler will implicitly apply the any keyword when you omit a type annotation.
Specifying Any Type in the tempConverter.ts File in the src Folder
Using Tuples
Using a Tuple in the main.ts File in the src Folder
Using Indexable Types
Using Indexable Types in the main.ts File in the src Folder
Only number and string values can be used as the keys for indexable types, but this is a helpful feature that I use in examples in later chapters.
Using Access Modifiers
JavaScript doesn’t support access protection, which means that classes, their properties, and their methods can all be accessed from any part of the application. There is a convention of prefixing the name of implementation members with an underscore (the _ character), but this is just a warning to other developers and is not enforced.
TypeScript provides three keywords that are used to manage access and that are enforced by the compiler. Table 6-2 describes the keywords.
Caution
During development, these keywords have limited effect in Angular applications because a lot of functionality is delivered through properties and methods that are specified in fragments of code embedded in data binding expressions. These expressions are evaluated at runtime in the browser, where there is no enforcement of TypeScript features. They become more important when you come to deploy the application, and it is important to ensure that any property or method that is accessed in a data binding expression is marked as public or has no access modifier (which has the same effect as using the public keyword).
The TypeScript Access Modifier Keywords
Keyword | Description |
|---|---|
public | This keyword is used to denote a property or method that can be accessed anywhere. This is the default access protection if no keyword is used. |
private | This keyword is used to denote a property or method that can be accessed only within the class that defines it. |
protected | This keyword is used to denote a property or method that can be accessed only within the class that defines it or by classes that extend that class. |
Using an Access Modifier in the tempConverter.ts File in the src Folder
The performCalculation method is marked as private, which means the TypeScript compiler will report an error code if any other part of the application tries to invoke the method.
Summary
In this chapter, I described the way that JavaScript supports working with objects and classes, explained how JavaScript modules work, and introduced the TypeScript features that are useful for Angular development. In the next chapter, I start the process of creating a realistic project that provides an overview of how different Angular features work together to create applications before digging into individual details in Part 2 of this book.