Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Learning Angular - Fourth Edition

You're reading from  Learning Angular - Fourth Edition

Product type Book
Published in Feb 2023
Publisher Packt
ISBN-13 9781803240602
Pages 446 pages
Edition 4th Edition
Languages
Authors (2):
Aristeidis Bampakos Aristeidis Bampakos
Profile icon Aristeidis Bampakos
Pablo Deeleman Pablo Deeleman
Profile icon Pablo Deeleman
View More author details

Table of Contents (17) Chapters

Preface 1. Building Your First Angular Application 2. Introduction to TypeScript 3. Organizing Application into Modules 4. Enabling User Experience with Components 5. Enrich Applications Using Pipes and Directives 6. Managing Complex Tasks with Services 7. Being Reactive Using Observables and RxJS 8. Communicating with Data Services over HTTP 9. Navigating through Application with Routing 10. Collecting User Data with Forms 11. Introduction to Angular Material 12. Unit Test an Angular Application 13. Bringing an Application to Production 14. Handling Errors and Application Debugging 15. Other Books You May Enjoy
16. Index

Functions, lambdas, and execution flow

Functions are the processing machines we use to analyze input, digest information, and apply the necessary transformations to data. Data can be provided either to transform the state of our application or to return an output that will be used to shape our application’s business logic or user interactivity.

Functions in TypeScript are not that different from regular JavaScript, except that, like everything else in TypeScript, they can be annotated with static types. Thus, they improve the compiler by providing the information it expects in their signature and the data type it aims to return, if any.

Annotating types in functions

The following example showcases how a regular function is annotated in TypeScript:

function sayHello(name: string): string {
    return 'Hello, ' + name;
}

There are two main differences from the usual function syntax in regular JavaScript. First, we annotate the parameters declared in the function signature, which makes sense since the compiler will want to check whether the data provided holds the correct type. In addition to this, we also annotate the returning value by adding the string type to the function declaration.

As mentioned in the previous section, the TypeScript compiler is smart enough to infer types when no annotation is provided. In this case, the compiler looks into the arguments provided and returns statements to infer a returning type from them.

Functions in TypeScript can also be represented as expressions of anonymous functions, where we bind the function declaration to a variable:

const sayHello = function(name: string): string {
    return 'Hello, ' + name;
}  

However, there is a downside to that approach. Although typing function expressions this way is allowed, thanks to type inference, the compiler is missing the type definition of the declared variable. We might assume that the inferred type of a variable that points to a function typed as a string is a string. Well, it’s not. A variable that points to an anonymous function ought to be annotated with a function type:

const sayHello: (name: string) => string = function(name: string): string {
    return 'Hello, ' + name;
}

The function type informs us of the types expected in the payload and the type returned by the function execution, if any. This whole block, which is of the form (arguments: type) => returned type, becomes the type annotation that our compiler expects.

Function parameters in TypeScript

Due to the type checking performed by the compiler, function parameters require special attention in TypeScript.

Optional parameters

Parameters are a core part of the type checking applied by the TypeScript compiler. Parameters are defined as optional by adding the character ? after the parameter name:

function greetMe(name: string, greeting?: string): string {
    if (!greeting) {
        greeting = 'Hello';
    }
    return greeting + ', ' + name;
}

To call the previous function, we can omit the second parameter in the function call:

greetMe('John');

So, an optional parameter is not set unless you explicitly pass it a value. It is more of a construct so that you can get help deciding what parameters are mandatory and which ones are optional. To exemplify this, consider the following function signature:

function add(mandatory: string, optional?: number) {}

We can invoke the previous function in the following ways:

add('some string');
add('some string', 3.14);

Both versions are valid. Be aware that optional parameters should be placed last in a function signature. Consider the following function:

function add(optional?: number, mandatory: string) {}

Both parameters of the previous function would be considered mandatory. Suppose that we call the function like so:

add(1);

The compiler would complain that you have not provided a value for the mandatory parameter. Remember, optional arguments are great, but place them last.

Default parameters

TypeScript gives us another feature to cope with default parameters, where we can set a default value that the parameter assumes when it’s not explicitly passed upon executing the function. The syntax is pretty straightforward, as we can see when we refactor the previous example:

function greetMe(name: string, greeting: string = 'Hello'): string {
    return `${greeting}, ${name}`;
}

Like optional parameters, default parameters must be put right after the required parameters in the function signature.

Rest parameters

One of the significant advantages of JavaScript flexibility when defining functions is the ability to accept an unlimited non-declared array of parameters. TypeScript can achieve the same behavior using the rest syntax. Essentially, we can define an additional parameter at the end of the arguments list prefixed by an ellipsis () and typed as an array:

function greetPeople(greeting: string, ...names: string[]): string {
    return greeting + ', ' + names.join(' and ') + '!';
}

Rest parameters are beneficial when we don’t know how many arguments will be passed in.

Function overloading

Method and function overloading are typical in other languages, such as C#. However, implementing this functionality in TypeScript clashes with the fact that JavaScript, which TypeScript is meant to compile to, does not implement any elegant way to integrate it out of the box. So, the only workaround possible requires writing function declarations for each of the overloads and then writing a general-purpose function that wraps the actual implementation, whose list of typed arguments and return types are compatible with all the others:

function hello(names: string): string
function hello(names: string[]): string
function hello(names: any, greeting?: string): string {
    let namesArray: string[];
    if (Array.isArray(names)) {
        namesArray = names;
    } else {
        namesArray = [names];
    }
    if (!greeting) {
        greeting = 'Hello';
    }
    return greeting + ', ' + namesArray.join(' and ') + '!';
}

In the preceding example, we create three different function signatures, each of which features different type annotations. We could even define different return types by annotating the wrapping function with type any.

Arrow functions

ES6 introduced the concept of fat arrow functions (also called lambda functions in other languages such as Python, C#, Java, or C++). The purpose of the arrow function is to simplify the general function syntax and provide a bulletproof way to handle the function scope traditionally handled by the this keyword. The first thing we notice is its minimalistic syntax, where, most of the time, we see arrow functions as single-line, anonymous expressions:

const double = x => x * 2;

The preceding function computes the double of a given number x and returns the result, although we do not see any function or return statements in the expression. If the function signature contains more than one argument, we need to wrap them all between parentheses:

const add = (x, y) => x + y;

Arrow functions can also contain statements by wrapping the whole implementation in curly braces:

const addAndDouble = (x, y) => {
    const sum = x + y;
    return sum * 2;
}

Still, what does this have to do with scope handling? The value of this can point to a different context, depending on where we execute the function. When we refer to this inside a callback, we lose track of the upper context, which usually leads us to use conventions such as assigning its value to a variable named self or that. It is this variable that is used later on within the callback. Statements containing interval or timeout functions make for a perfect example of this:

function delayedGreeting(name): void {
    this.name = name;
    this.greet = function(){
        setTimeout(function() {
            console.log('Hello ' + this.name);
        }, 0);
    }
}
const greeting = new delayedGreeting('John');
greeting.greet();

If we execute the preceding script, it won’t print the name John in the browser console as expected because it modifies the scope of this when evaluating the function inside the timeout call. If we modify the code according to the following, it will do the trick:

function delayedGreeting(name): void {
    this.name = name;
    this.greet = function() {
        setTimeout(() => 
            console.log('Hello ' + this.name)
        , 0);
    }
}

Even if we break down the statement contained in the arrow function into several lines of code wrapped by curly braces, the scope of this keeps pointing to the instance itself outside the timeout call, allowing for more elegant and clean syntax.

Now that we have acquired basic knowledge of functions in TypeScript and how they are executed, we can continue our journey to the typing system and learn some of the most common TypeScript features used in Angular.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}