Book Image

Learning Angular - Fourth Edition

By : Aristeidis Bampakos, Pablo Deeleman
5 (1)
Book Image

Learning Angular - Fourth Edition

5 (1)
By: Aristeidis Bampakos, Pablo Deeleman

Overview of this book

As Angular continues to reign as one of the top JavaScript frameworks, more developers are seeking out the best way to get started with this extraordinarily flexible and secure framework. Learning Angular, now in its fourth edition, will show you how you can use it to achieve cross-platform high performance with the latest web techniques, extensive integration with modern web standards, and integrated development environments (IDEs). The book is especially useful for those new to Angular and will help you to get to grips with the bare bones of the framework to start developing Angular apps. You'll learn how to develop apps by harnessing the power of the Angular command-line interface (CLI), write unit tests, style your apps by following the Material Design guidelines, and finally, deploy them to a hosting provider. Updated for Angular 15, this new edition covers lots of new features and tutorials that address the current frontend web development challenges. You’ll find a new dedicated chapter on observables and RxJS, more on error handling and debugging in Angular, and new real-life examples. By the end of this book, you’ll not only be able to create Angular applications with TypeScript from scratch, but also enhance your coding skills with best practices.
Table of Contents (17 chapters)
Other Books You May Enjoy

Common TypeScript features

TypeScript has some general features that don’t apply to classes, functions, or parameters but make coding more efficient and fun. The idea is that the fewer lines of code we write, the better it is. It’s not only about fewer lines but also about making things more straightforward. There are many such features in ES6 that TypeScript has also implemented. In the following sections, we’ll name a few that you will likely use in an Angular project.

Spread parameter

A spread parameter uses the same ellipsis syntax as the rest parameter but is used inside the body of a function. Let’s illustrate this with an example:

const newItem = 3;
const oldArray = [1, 2];
const newArray = [...oldArray, newItem];

In the preceding snippet, we add an item to an existing array without changing the old one. The old array still contains 1, 2, whereas the new array contains 1, 2, and 3. The current behavior is called immutability, which means not changing the old array but rather creating a new state from it. It is a principle used in functional programming as a paradigm and for performance reasons.

We can also use a spread parameter on objects:

const oldPerson = { name: 'John' };
const newPerson = { ...oldPerson, age: 20 };

In the preceding snippet, we are creating a merge between the two objects. Like in the array example, we don’t change the previous variable, oldPerson. Instead, the newPerson variable takes the information from the oldPerson variable and adds its new values to it.

Template strings

Template strings are all about making your code clearer. Consider the following:

const url = 'http://path_to_domain' +
    'path_to_resource' +
    '?param=' + parameter +
    '&param2=' + parameter2;

So, what’s wrong with the previous snippet? The answer is readability. It’s hard to imagine what the resulting string will look like but editing the code by mistake and producing an unwanted result is also easy. To overcome this, we can use template strings in the following way:

const url =

The preceding syntax is a much more condensed expression and much easier to read.


Generics are expression indicating a general code behavior that we can employ, regardless of the data type. They are often used in collections because they have similar behavior, regardless of the type. They can, however, be used on other constructs such as methods. The idea is that generics should indicate if you are about to mix types in a way that isn’t allowed:

function method<T>(arg: T): T {
    return arg;

In the preceding example, the type of T is not evaluated until we use the method. As you can see, its type varies, depending on how you call it. It also ensures that you are passing the correct type of data. Suppose that the preceding method is called in this way:


We specify that T should be a string, but we insist on passing it a value as a number. The compiler clearly states that this is not correct. You can, however, be more specific on what T should be. You can make sure that it is an array type so that any value you pass must adhere to this:

function method<T>(arg: T[]): T[] {
    return arg;
class CustomPerson extends Array {}
class Person {}
const people: Person[] = [];
const newPerson = new CustomPerson();

In the preceding case, we decide that T should be of Person or CustomPerson type and that the parameter needs to be of the array type. If we try to pass a single object, the compiler will complain:

const person = new Person();

Alternatively, we can define that T should adhere to an interface like this:

interface Shape {
    area(): number;
class Square implements Shape {
    area() { return 1; }
class Circle implements Shape {
    area() { return 2; }
function allAreas<T extends Shape>(...args: T[]): number {
    let total = 0;
    args.forEach (x => {
        total += x.area();
    return total;
allAreas(new Square(), new Circle());

Generics are powerful to use if you have a typical behavior with many different data types. You probably won’t be writing custom generics, at least not initially, but it’s good to know what is going on.

Optional chaining

The optional chaining in TypeScript is a powerful feature that can help us with refactoring and simplifying our code. In a nutshell, it can guide our TypeScript code to ignore the execution of a statement unless a value has been provided somewhere in that statement. Let’s see optional chaining with an example:

const square = new Square();

In the preceding snippet, we create a square object using the Square class of the previous section. Later, we read the value of the area method by making sure that the object has a value set before reading it:

if (square !== undefined) {
    const area = square.area();

The previous snippet is a precautionary step in case our object has been modified in the meantime. If we do not check the object and it has become undefined, the compiler will throw an error. However, we can use optional chaining to make the previous statement more readable:

const area = square?.area();

The character ? after the square object ensures that the area method will be accessed only if the object has a value. The case where optional chaining shines is in more complicated scenarios with much more values to check, such as the following:

const width = square?.area()?.width;

In the preceding scenario, we assume that the area property is an optional object that contains a width property. In that case, we would need to check values for both square and area.

Although the optional chaining feature was added in an earlier version of TypeScript, it has become very popular in the latest versions of Angular with its support in component templates.

Nullish coalescing

The nullish coalescing feature in TypeScript looks similar to the optional chaining we learned about in the previous section. However, it is more related to providing a default value when a variable is not set. Consider the following example that assigns a value to the mySquare variable only if the square object exists:

const mySquare = square ? square : new Square();

The previous statement is called a ternary operator and operates like a conditional statement. If the square object is undefined or null, the mySquare variable will take the default value of a new square object. We can rewrite the previous expression using nullish coalescing:

const mySquare = square ?? new Square();

Although the nullish coalescing feature was added in an earlier version of TypeScript, it has become very popular in the latest versions of Angular with its support in component templates.