TypeScript 2.x for Angular Developers

3 (2 reviews total)
By Christian Nwamba
  • Instant online access to over 7,500+ books and videos
  • Constantly updated with 100+ new titles each month
  • Breadth and depth in over 1,000+ technologies
  1. From Loose Types to Strict Types

About this book

TypeScript, a superset of JavaScript, is the default language for building Angular applications from Google. TypeScript 2.0 adds optional static types, classes, and modules to JavaScript, to enable great tooling and better structuring of large JavaScript applications.

This book will teach you how to leverage the exciting features of TypeScript while working on Angular projects to build scalable, data-intensive web applications. You will begin by setting up and installing TypeScript and then compile it with JavaScript. You will then learn to write simple JavaScript expressions with TypeScript. You will then go through some built in TypeScript types and accessors. Further you will build web components using TypeScript Interfaces and Decorators. You will go through the Angular form module, which will enable you to write predictable typed forms with TypeScript and learn to use typed DOM events. You will also build a single-page application using the Router module. Lastly, you will consume API data with Angular's HTTP Module and handle responses with RxJS observables. At the end of the book, you will go through different testing and debugging techniques.

Publication date:
December 2017
Publisher
Packt
Pages
240
ISBN
9781786460554

 

Chapter 1. From Loose Types to Strict Types

JavaScript is loosely typed. It's worth repeating, JavaScript is loosely typed. Notice how the sentence is passive--we cannot categorically hold someone responsible for the loose-type nature of JavaScript just as we can't do so for other famous glitches of JavaScript.

A detailed discussion on what loose-types and loosely typed languages are will help aid your understanding of the problem that we plan to solve with this book.

When a programming language is loosely typed, it means that the data passed around using variables, functions, or whatever member applicable to the language does not have a defined type. A variable x could be declared, but the kind of data it holds is never certain. Loosely typed languages are contrary to strongly typed languages, which enforce that every declared member must strictly define what sort of data it can hold.

These types are categorized into:

  • Strings
  • Numbers (int, float, and so on.)
  • Data structures (arrays, lists, objects, maps, and so on.)
  • Boolean (true and false)

JavaScript, PHP, Perl, Ruby, and so on, are all examples of loosely typed languages. Java, C, C#, are examples of strongly typed languages.

In loosely typed languages, a member may be initially defined as a string. Down the line, this member could end up storing a number, a boolean, or even a data structure. This instability leads us to the implications of loosely typed languages.

 

Term definitions


Before we keep moving, it would be nice to define the common jargon you may have met or will meet with in the course of understanding loose and strict types:

  • Members: These are the features of a language that describe how the data is stored and manipulated. Variables, functions, properties, classes, interfaces, and so on, are all examples of the possible members a language can have.
  • Declared versus defined versus assigned: When a variable is initialized with no value, it is said to be declared. When it is declared and has a type, it is said to be defined. When the variable has a value, whether typed or not, it is assigned.
  • Types: These are used to categorize the data based on how they are parsed and manipulated. For example, numbers, strings, booleans, arrays, and so on.
  • Values: The data assigned to a given member is known as the member's value.
 

Implications of loose types


Let's start out with an example to show how loosely typed languages behave:

// Code 1.1

// Declare a variable and assign a value
var x = "Hello";

// Down the line
// you might have forgotten 
// about the original value of x
//
//
// Re-assign the value
x = 1;

// Log value
console.log(x); // 1

The variable x was initially declared and assigned a string value, Hello. The same x  got re-assigned to a numeric value, 1. Nothing went wrong; the code was interpreted and when we logged the value to the console, it logged the latest value of x, which is 1.

This is not just a string-number thing; the same thing applies to every other type, including complex data structures:

// Code 1.2

var isCompleted;

// Assign null
isCompleted = null;
console.log('When null:', isCompleted);

// Re-assign a boolean
isCompleted = false;
console.log('When boolean:', isCompleted);

// Re-assign a string
isCompleted = 'Not Yet!';
console.log('When string:', isCompleted);

// Re-assign a number
isCompleted = 0;
console.log('When number:', isCompleted);

// Re-assign an array
isCompleted = [false, true, 0];
console.log('When array:', isCompleted);

// Re-assign an object
isCompleted = {status: true, done: "no"};
console.log('When object:', isCompleted);

/**
* CONSOLE:
*
* When null: null
* When boolean: false
* When string: Not Yet!
* When number: 0
* When array: [ false, true, 0 ]
* When object: { status: true, done: 'no' }
*/

The important thing to note here is not that the values are changing. Rather, it's the fact that both values and types are changing. The change in the type does not affect the execution. Everything works fine, and we have our expected result in the console.

The function parameters and return types are not left out either. You can have a function signature that accepts a string parameter, but JavaScript will keep silent when you, or any other developer, pass in a number while calling the function:

function greetUser( username ) {
 return `Hi, ${username}`
}

console.log('Greet a user string: ', greetUser('Codebeast'))
console.log('Greet a boolean: ', greetUser(true))
console.log('Greet a number: ', greetUser(1))

/**
 * CONSOLE:
 *
 * Greet a user string: Hi, Codebeast
 * Greet a boolean: Hi, true
 * Greet a number: Hi, 1
 */

If you're coming from a strong-type background and have no previous experience with loosely typed languages, the preceding example must feel weird. This is because in strongly typed languages, it's hard to change the type of the particular member (variables, functions, and so on).

So, what is the implication to take note of? The obvious implication is that the members that are loosely typed are inconsistent. Therefore, their value types can change, and this is something that you, the developer, will need to watch out for. There are challenges in doing so; let's talk about them.

The problem

Loose types are tricky. At first glance, they appear to be all nice and flexible to work with--flexibility, as in giving you the freedom to change types anytime and anywhere, without the interpreter screaming errors like other strongly typed languages do. Just like any other form of freedom, this one also comes with a price.

The major problem is inconsistency. It is very easy to forget the original type for a member. This could lead you to handling, say, a string as if it were still a string when its value is now Boolean. Let's see an example:

function greetUser( username ) {
 // Reverse the username
 var reversed = username.split('').reverse().join('');
 return `Hi, ${reversed}`
}

console.log('Greet a correct user: ', greetUser('Codebeast'))


 * CONSOLE:
 *
 * Greet a correct user: Hi, tsaebedoC
 */

In the preceding example, we have a function that greets the users based on their usernames. Before it does the greeting, it first reverses the username. We can call the function by passing in a username string.

What happens when we pass in a Boolean or some other type that does not have a split method? Let's check it out:

// Code 1.4

function greetUser( username ) {
 var reversed = username.split('').reverse().join('');
 return `Hi, ${reversed}`
}

console.log('Greet a correct user: ', greetUser('Codebeast'))

// Pass in a value that doesn't support
// the split method
console.log('Greet a boolean: ',greetUser(true))


 * CONSOLE:
 *
 * Greet a correct user: Hi, tsaebedoC
 * /$Path/Examples/chapter1/1.4.js:2
 * var reversed = username.split('').reverse().join('');
                          ^
 * TypeError: username.split is not a function
 */

The first log output, which prints the greeting with a string, comes out fine. But the second attempt fails because we passed in a Boolean. In as much as everything in JavaScript is an object, a Boolean does not have a split method. The image ahead shows a clear output of the preceding example:

Yes, you might be thinking that you're the author of this code; why would you pass in a Boolean when you designed the function to receive a string? Remember that a majority of the code that we write in our lifetime is not maintained by us, but by our colleagues.

When another developer picks up greetUser and decides to use the function as an API without digging the code's source or documentation, there is a high possibility that he/she won't pass in the right value type. This is because he/she is blind. Nothing tells him/her what is right and what is not. Even the name of the function is not obvious enough to make her pass in a string.

JavaScript evolved. This evolution was not just experienced internally but was also seen in its vast community. The community came up with best practices on tackling the challenges of the loose-type nature of JavaScript.

Mitigating loose-type problems

JavaScript does not have any native obvious solution to the problems that loose types bring to the table. Rather, we can use all forms of manual checks using JavaScript's conditions to see whether the value in question is still of the intended type.

We are going to have a look at some examples where manual checks are applied in order to retain the integrity of the value types.

The popular saying that Everything is an Object in JavaScript is not entirely true (https://blog.simpleblend.net/is-everything-in-javascript-an-object/). There are Objects and there are Primitives. Strings, numbers, Boolean, null, undefined, are primitives but are handled as objects only during computation. That's why you can call something like .trim() on a string. Objects, arrays, dates, and regular expressions are valid objects. It's mind-troubling to say that an object is an object, but that is JavaScript for you.

The typeof operator

The typeof operator is used to check the type of a given operand. You can use the operator to control the harm of loose types. Let's see some examples:

// Code 1.5
function greetUser( username ) {
 if(typeof username !== 'string') {
   throw new Error('Invalid type passed');
 };
 var reversed = username.split('').reverse().join('');
 return `Hi, ${reversed}`
}

console.log('Greet a correct user: ', greetUser('Codebeast'))
console.log('Greet a boolean: ',greetUser(true))

Rather than waiting for the system to tell us that we're wrong when an invalid type is passed in, we catch the error as early as possible and throw a custom and more friendly error, as shown in the following screenshot:

The typeof operator returns a string, which represents the value's type. The typeof operator is not entirely perfect and should only be used when you are sure about how it works. See the following issue:

function greetUser( user ) {
 if ( typeof user !== 'object' ) {
   throw new Error('Type is not an object');
 }
 return `Hi, ${user.name}`;
}

console.log('Greet a correct user: ', greetUser( {name: 'Codebeast', age: 24 } ))
// Greet a correct user: Hi, Codebeast

console.log('Greet a boolean: ', greetUser( [1, 2, 3] ))
// Greet a boolean: Hi, undefined

You may have expected an error to be thrown when the function was called with an array for the second time. Instead, the program got past the check and executed user.name before realizing that it is undefined. Why did it get past this check? Remember that an array is an object. Therefore, we need something more specific to catch the check. Date and regex could have passed the check as well, even though that may not have been the intent.

The toString method

The toString method is prototypically inherited by all the objects and wrapped objects (primitives). When you call this method on them, it returns a string token of the type. See the following examples:

Object.prototype.toString.call([]);// [object Array]Object.prototype.toString.call({});// [object Object]Object.prototype.toString.call('');// [object String]Object.prototype.toString.call(newDate());// [object Date]
// etc

Now you can use this to check the types, as shown by Todd Motto (https://toddmotto.com/understanding-javascript-types-and-reliable-type-checking/#true-object-types):

var getType = function (elem) {
 return Object.prototype.toString.call(elem).slice(8, -1);
};
var isObject = function (elem) {
 return getType(elem) === 'Object';
};

// You can use the function
// to check types
if (isObject(person)) {
 person.getName();
}

What the preceding example does is check the part of the string returned by the toString method to determine its type.

 

Final Note


The examples we saw previously are just an overkill for a simple type check. If JavaScript had strict type features, we wouldn't have gone through this stress. In fact, this chapter would never have existed.

Imagine that JavaScript could do this:

function greet( username: string ) {
 return `Hi, ${username}`;
}

We wouldn't have gone through all that type checking hell because the compiler (as well as the editors) would have thrown errors when it encountered type inconsistency.

This is where TypeScript comes in. Luckily, with TypeScript, we can write code that looks like the preceding one, and we can have it transpiled to JavaScript.

 

Summary


Throughout this book, we will be talking about TypeScript for building not just JavaScript apps but also Angular apps. Angular is a JavaScript framework; therefore, it will be characterized with the discussed limitations unless mitigated with TypeScript.

Now that you know the problem at hand, buckle up while we dig Angular with the possible solutions that TypeScript provides.

So far, so good! We have been able to discuss the following concerns to help us move forward:

  • Understanding loose types
  • Differences between loose types and strict types
  • Challenges of loosely typed programming languages, including JavaScript
  • Mitigating the effects of loose types

About the Author

  • Christian Nwamba

    Christian Obinna Nwamba is a Lagos, Nigeria-based full stack engineer, developer, and evangelist. He spends most of his life building user experiences with JavaScript and spreading the word to other developers through conferences, meetups, and technical articles.

    He has worked with quite a few interesting SaaS companies, such as Cloudinary, Pusher, and Auth0, and has published articles on popular blogs, such as Sitepoint, Scotch.io, Codementor, and Web Designer Depot. This is his first book and he's very proud of the effort he put in to make it enjoyable for the readers.

    He has a lot of interest in community building and efforts, especially in Africa. He does this by organizing and facilitating meetups/conferences (forLoop Africa, Angular Nigiera, GDGs, and more).

    Browse publications by this author

Latest Reviews

(2 reviews total)
NOT FOUND - and No reply from you! THIEVES.
didaktisch sehr gut aufbereitet
Book Title
Access this book, plus 7,500 other titles for FREE
Access now