Type Script
Type Script
Intro
TypeScript is Typed JavaScript. TypeScript adds types to JavaScript to help you speed up the development by
catching errors before you even run the JavaScript code.
TypeScript is an open-source programming language that builds on top of JavaScript. It works on any
browser, any OS, any environment that JavaScript runs.
TypeScript builds on top of JavaScript. First, you write the TypeScript code. Then, you compile the TypeScript
code into plain JavaScript code using a TypeScript compiler.
Once you have the plain JavaScript code, you can deploy it to any environments that JavaScript runs.
TypeScript uses the JavaScript syntaxes and adds additional syntaxes for supporting Types.
If you have a JavaScript program that doesn’t have any syntax errors, it is also a TypeScript program. It means
that all JavaScript programs are TypeScript programs. This is very helpful if you’re migrating an existing
JavaScript codebase to TypeScript.
The following diagram shows the relationship between TypeScript and JavaScript:
1
Why TypeScript
The main goals of TypeScript are:
Types increase productivity by helping you avoid many mistakes. By using types, you can catch bugs at the
compile-time instead of having them occurring at runtime.
function add(x, y) {
return x + y;
}
Code language: JavaScript (javascript)
If you get the values from HTML input elements and pass them into the function, you may get an unexpected
result:
2
The reason is that the input1.value and input2.value are strings, not numbers. When you use the operator + to add
two strings, it concatenates them into a single string.
When you use TypeScript to explicitly specify the type for the parameters like this:
In this function, we added the number types to the parameters. The function add() will accept only numbers,
not any other values.
… the TypeScript compiler will issue an error if you compile the TypeScript code into JavaScript. Hence, you
can prevent the error from happening at runtime.
TypeScript supports the upcoming features planned in the ES Next for the current JavaScript engines. It means
that you can use the new JavaScript features before web browsers (or other environments) fully support them.
Every year, TC39 releases several new features for ECMAScript, which is the standard of JavaScript. The feature
proposals typically go through five stages:
Stage 0: Strawperson
Stage 1: Proposal
Stage 2: Draft
Stage 3: Candidate
Stage 4: Finished
"Hello"
Code language: TypeScript (typescript)
3
From the value, you can tell that its type is string. Also, the following value is a number:
2020
Code language: TypeScript (typescript)
let box;
box = "hello";
box = 100;
Code language: TypeScript (typescript)
let box;
console.log(typeof(box)); // undefined
box = "Hello";
console.log(typeof(box)); // string
box = 100;
console.log(typeof(box)); // number
Code language: TypeScript (typescript)
In this example, the first statement defines the variable without assigning a value. Its type is undefined.
Then, we assign "Hello" to box variable and show its type. The type of the box variable now changes to string.
Finally, we assign 100 to the box variable. This time, the type of the box variable changes to number.
As you can see, as soon as the value is assigned, the type of the variable changes.
And you don’t need to explicitly tell JavaScript the type. JavaScript will automatically infer the type from the
value.
function getProduct(id){
return {
id: id,
name: `Awesome Gadget ${id}`,
4
price: 99.5
}
}
Code language: TypeScript (typescript)
The following uses the getProduct() function to retrieve the product with id 1 and shows its data:
Output:
The issue with this code is that the product object doesn’t have the Name property. It has the name property with
the first letter n in lowercase.
However, you can only know it until you run the script.
Referencing a property that doesn’t exist on the object is a common issue when working in JavaScript.
The following example defines a new function that outputs the product information to the Console:
Output:
This time we pass the arguments in the wrong order to the showProduct() function. This is another common
problem that you often have when working with JavaScript.
5
How Typescript solves the problems of dynamic types
To fix the problem of referencing a property that doesn’t exist on an object, you do the following steps:
First, define the “shape” of the product object using an interface. Note that you’ll learn about the interface in a
later tutorial.
interface Product{
id: number,
name: string,
price: number
};
Code language: CSS (css)
When you reference a property that doesn’t exist, the code editor will inform you immediately:
And when you hover the mouse cursor on the error, you’ll see a hint that helps you to solve the issue:
6
To solve the problem of passing the arguments in the wrong order, you explicitly assign types to function
parameters:
And when you pass the arguments of the wrong types to the showProduct() function, you’ll receive an error:
Summary
JavaScript is dynamically typed. It offers flexibility but also creates many problems.
TypeScript adds an optional type system to JavaScript to solve these problems.
Type Annotations
What is Type Annotation in TypeScript
TypeScript uses type annotations to explicitly specify types for identifiers such variables, functions, objects,
etc.
TypeScript uses the syntax : type after an identifier as the type annotation, where type can be any valid type.
Once an identifier is annotated with a type, it can be used as that type only. If the identifier is used as a
different type, the TypeScript compiler will issue an error.
The following syntax shows how to specify type annotations for variables and constants:
In this syntax, the type annotation comes after the variable or constant name and is preceded by a colon ( :).
counter = 1;
Error:
You can both use a type annotation for a variable and initialize it in a single statement like this:
In this example, we use the number annotation for the counter variable and initialize it to one.
In this example, the name variable gets the string type, the age variable gets the number type, and the active variable
gets the boolean type.
To annotate an array type you use use a specific type followed by a square bracket : type[] :
8
let arrayName: type[];
Code language: JavaScript (javascript)
Objects
To specify a type for an object, you use the object type annotation. For example:
let person: {
name: string;
age: number
};
person = {
name: 'John',
age: 25
}; // valid
Code language: JavaScript (javascript)
In this example, the person object only accepts an object that has two properties: name with the string type
and age with the number type.
The following shows a function annotation with parameter type annotation and return type annotation:
In this example, you can assign any function that accepts a string and returns a string to the greeting variable:
The following causes an error because the function that is assigned to the greeting variable doesn’t match with
its function type.
greeting = function () {
console.log('Hello');
};
Code language: JavaScript (javascript)
9
Error:
Type '() => void' is not assignable to type '(name: string) => string'. Type 'void' is not assignable to type 'string'.
Code language: JavaScript (javascript)
Summary
Use type annotations with the syntax : [type] to explicitly specify a type for a variable, function, function
return value, etc.
Basic Types
TypeScript Number
Summary: in this tutorial, you’ll learn about the TypeScript number data types.
All numbers in TypeScript are either floating-point values or big integers. The floating-point numbers have the
type number while the big integers get the type bigint.
The following shows how to declare a variable that holds a floating-point value:
As in JavaScript, TypeScript supports the number literals for decimal, hexadecimal, binary, and octal literals:
Decimal numbers
The binary number uses a leading zero followed by a lowercase or uppercase letter “B” e.g., 0b or 0B :
Octal Numbers
An octal number uses a leading zero followed the letter o (since ES2015) 0o. The digits after 0o are numbers in
the range 0 through 7:
Hexadecimal numbers use a leading zero followed by a lowercase or uppercase letter X (0x or 0X). The digits
after the 0x must be in the range (0123456789ABCDEF). For example:
JavaScript has the Number type (with the letter N in uppercase) that refers to the non-primitive boxed object.
You should not use this Number type as much as possible in TypeScript.
Big Integers
The big integers represent the whole numbers larger than 2 53 – 1. A Big integer literal has the n character at the
end of an integer literal like this:
All numbers in TypeScript are either floating-point values that get the number type or big integers that
get the bigint type.
Avoid using the Number type as much as possible.
TypeScript String
Like JavaScript, TypeScript uses double quotes (") or single quotes (') to surround string literals:
TypeScript also supports template strings that use the backtick (`) to surround characters.
The template strings allow you to create multi-line strings and provide the string interpolation features.
11
The following example shows how to create multi-line string using the backtick (`):
String interpolations allow you to embed the variables into the string like this:
console.log(profile);
Code language: JavaScript (javascript)
Output:
I'm John.
I'm a Web Developer.
Code language: PHP (php)
Summary
TypeScript Boolean
The TypeScript boolean type allows two values: true and false. It’s one of the primitive types in TypeScript. For
example:
JavaScript has the Boolean type that refers to the non-primitive boxed object. The Boolean type has the letter B in
uppercase, which is different from the boolean type.
12
TypeScript object Type
Summary: in this tutorial, you’ll learn about the TypeScript object type and how to write more
accurate object type declarations.
The TypeScript object type represents all values that are not in primitive types.
number
bigint
string
boolean
null
undefined
symbol
employee = {
firstName: 'John',
lastName: 'Doe',
age: 25,
jobTitle: 'Web Developer'
};
console.log(employee);
Code language: JavaScript (javascript)
Output:
{
firstName: 'John',
lastName: 'Doe',
age: 25,
jobTitle: 'Web Developer'
}
Code language: CSS (css)
employee = "Jane";
Code language: JavaScript (javascript)
13
Error:
The employee object is an object type with a fixed list of properties. If you attempt to access a property that
doesn’t exist on the employee object, you’ll get an error:
console.log(employee.hireDate);
Code language: CSS (css)
Error:
Note that the above statement works perfectly fine in JavaScript and returns undefined instead.
To explicitly specify properties of the employee object, you first use the following syntax to declare
the employee object:
let employee: {
firstName: string;
lastName: string;
age: number;
jobTitle: string;
};
Code language: CSS (css)
And then you assign the employee object to a literal object with the described properties:
employee = {
firstName: 'John',
lastName: 'Doe',
age: 25,
jobTitle: 'Web Developer'
};
Code language: JavaScript (javascript)
Or you can combine both syntaxes in the same statement like this:
let employee: {
firstName: string;
lastName: string;
age: number;
jobTitle: string;
}={
firstName: 'John',
14
lastName: 'Doe',
age: 25,
jobTitle: 'Web Developer'
};
Code language: JavaScript (javascript)
object vs. Object
TypeScript has another type called Object with the letter O in uppercase. It’s important to understand the
differences between them.
The object type represents all non-primitive values while the Object type describes the functionality of all objects.
For example, the Object type has the toString() and valueOf() methods that can be accessible by any object.
TypeScript has another type called empty type denoted by {} , which is quite similar to the object type.
The empty type {} describes an object that has no property on its own. If you try to access a property on such
object, TypeScript will issue a compile-time error:
Error:
But you can access all properties and methods declared on the Object type, which is available on the object
via prototype chain:
console.log(vacant.toString());
Code language: JavaScript (javascript)
Output:
[object Object]
Code language: JSON / JSON with Comments (json)
Summary
Summary: in this tutorial, you’ll learn about the TypeScript array type and its basic operations.
A TypeScript array is an ordered list of data. To declare an array that holds values of a specific type, you use the
following syntax:
or use the push() method:
skills.push('Software Design');
Code language: JavaScript (javascript)
Once you define an array of a specific type, TypeScript will prevent you from adding incompatible values to
the array.
skills.push(100);
Code language: CSS (css)
When you extract an element from the array, TypeScript can do type inference. For example:
Output:
string
In this example, we extract the first element of the skills array and assign it to the skill variable.
Since an element in a string array is a string, TypeScript infers the type of the skill variable to string as shown in
the output.
TypeScript arrays can access the properties and methods of a JavaScript. For example, the following uses the
length property to get the number of element in an array:
And you can use all the useful array method such as forEach(), map(), reduce(), and filter(). For example:
Output:
[ 2, 4, 6 ]
Code language: JSON / JSON with Comments (json)
Storing values of mixed types
The following illustrates how to declare an array that hold both strings and numbers:
17
In this case, TypeScript infers the scores array as an array of string | number.
In TypeScript, an array is an ordered list of values. An array can store a mixed type of values.
To declare an array of a specific type, you use the let arr: type[] syntax.
TypeScript Tuple
Summary: in this tutorial, you’ll learn about the TypeScript Tuple type and its usages.
For example, you can use a tuple to represent a value as a pair of a string and a number:
The order of values in a tuple is important. If you change the order of values of the skill tuple to [5,
"Programming"], you’ll get an error:
Error:
For this reason, it’s a good practice to use tuples with data that is related to each other in a specific order.
For example, you can use a tuple to define an RGB color that always comes in a three-number pattern:
18
(r,g,b)
For example:
Since TypeScript 3.0, a tuple can have optional elements specified using the question mark (?) postfix.
For example, you can define an RGBA tuple with the optional alpha channel value:
Note that the RGBA defines colors using the red, green, blue, and alpha model. The alpha specifies the opacity
of the color.
Summary
A tupple is an array with a fixed number of elements whose types are known.
TypeScript Enum
Summary: in this tutorial, you’ll learn about the TypeScript enum type and how to use it effectively.
What is an enum
An enum is a group of named constant values. Enum stands for enumerated type.
19
In this syntax, the constant1, constant2, etc., are also known as the members of the enum.
The following example creates an enum that represents the months of the year:
enum Month {
Jan,
Feb,
Mar,
Apr,
May,
Jun,
Jul,
Aug,
Sep,
Oct,
Nov,
Dec
};
Code language: TypeScript (typescript)
In this example, the enum name is Month and constant values are Jan, Feb, Mar, and so on.
The following declares a function that uses the Month enum as the type of the month parameter:
console.log(isItSummer(Month.Jun)); // true
Code language: JavaScript (javascript)
20
This example uses constant values including Jan, Feb, Mar, … in the enum rather than magic values like 1, 2, 3,…
This makes the code more obvious.
It is a good practice to use the constant values defined by enums in the code.
However, the following example passes a number instead of an enum to the isItSummer() function. And it works.
console.log(isItSummer(6)); // true
Code language: JavaScript (javascript)
This example uses a number (6) instead of a constant defined by the Month enum. and it works.
var Month;
(function (Month) {
Month[Month["Jan"] = 0] = "Jan";
Month[Month["Feb"] = 1] = "Feb";
Month[Month["Mar"] = 2] = "Mar";
Month[Month["Apr"] = 3] = "Apr";
Month[Month["May"] = 4] = "May";
Month[Month["Jun"] = 5] = "Jun";
Month[Month["Jul"] = 6] = "Jul";
Month[Month["Aug"] = 7] = "Aug";
Month[Month["Sep"] = 8] = "Sep";
Month[Month["Oct"] = 9] = "Oct";
Month[Month["Nov"] = 10] = "Nov";
Month[Month["Dec"] = 11] = "Dec";
})(Month || (Month = {}));
Code language: JavaScript (javascript)
{
'0': 'Jan',
'1': 'Feb',
'2': 'Mar',
'3': 'Apr',
'4': 'May',
'5': 'Jun',
'6': 'Jul',
'7': 'Aug',
'8': 'Sep',
'9': 'Oct',
'10': 'Nov',
'11': 'Dec',
21
Jan: 0,
Feb: 1,
Mar: 2,
Apr: 3,
May: 4,
Jun: 5,
Jul: 6,
Aug: 7,
Sep: 8,
Oct: 9,
Nov: 10,
Dec: 11
}
Code language: JavaScript (javascript)
As you can see clearly from the output, a TypeScript enum is an object in JavaScript. This object has named
properties declared in the enum. For example, Jan is 0 and Feb is 1.
The generated object also has number keys with string values representing the named constants.
That’s why you can pass a number into the function that accepts an enum. In other words, an enum member
is both a number and a defined constant.
TypeScript defines the numeric value of an enum’s member based on the order of that member that appears
in the enum definition. For example, Jan takes 0, Feb gets 1, etc.
It’s possible to explicitly specify numbers for the members of an enum like this:
enum Month {
Jan = 1,
Feb,
Mar,
Apr,
May,
Jun,
Jul,
Aug,
Sep,
Oct,
Nov,
Dec
};
Code language: TypeScript (typescript)
In this example, the Jan constant value takes 1 instead of 0. The Feb takes 2, and the Mar takes 3, etc.
22
When to use an enum
For example, you can use an enum for the approval status:
enum ApprovalStatus {
draft,
submitted,
approved,
rejected
};
const request = {
id: 1,
status: ApprovalStatus.approved,
description: 'Please approve this request'
};
Summary: in this tutorial, you will learn about the TypeScript any type and how to use it properly in your code.
Sometimes, you may need to store a value in a variable. But you don’t know its type at the time of writing the
program. And the unknown value may come from a third party API or user input.
23
In this case, you want to opt-out of the type checking and allow the value to pass through the compile-time
check.
To do so, you use the any type. The any type allows you to assign a value of any type to a variable:
Output:
However, when you use the currentLocation to access object properties, TypeScript also won’t carry any check:
console.log(currentLocation.x);
Code language: CSS (css)
Output:
undefined
Code language: JavaScript (javascript)
The any type provides you with a way to work with existing JavaScript codebase. It allows you to gradually opt-
in and opt-out of type checking during compilation. Therefore, you can use the any type for migrating a
JavaScript project over to TypeScript.
If you declare a variable without specifying a type, TypeScript assumes that you use the any type. This feature
is called type inference. Basically, TypeScript guesses the type of the variable. For example:
let result;
Code language: JavaScript (javascript)
In this example, TypeScript infers the type for you. This practice is called implicit typing.
24
Note that to disable implicit typing to the any type, you change the noImplicitAny option in the tsconfig.json file to
true. You’ll learn more about the tsconfig.json in the later tutorial.
If you declare a variable with the object type, you can also assign it any value.
However, you cannot call a method on it even the method actually exists. For example:
In this example, the TypeScript compiler doesn’t issue any warning even the willExist() method doesn’t exist at
compile time because the willExist() method might available at runtime.
However, if you change the type of the result variable to object, the TypeScript compiler will issue an error:
Error:
The TypeScript any type allows you to store a value of any type. It instructs the compiler to skip type
checking.
Use the any type to store a value that you don’t actually know its type at the compile-time or when you
migrate a JavaScript project over to a TypeScript project.
Summary: in this tutorial, you will learn about the TypeScript void type and how to use it as the return type of
functions that do not return any value.
The void type denotes the absence of having any type at all. It is a little like the opposite of the any type.
25
Typically, you use the void type as the return type of functions that do not return a value. For example:
It is a good practice to add the void type as the return type of a function or a method that doesn’t return any
value. By doing this, you can gain the following benefits:
Improve clarity of the code: you do not have to read the whole function body to see if it returns
anything.
Ensure type-safe: you will never assign the function with the void return type to a variable.
Notice that if you use the void type for a variable, you can only assign undefined to that variable. In this case,
the void type is not useful. For example:
Use the void type as the return type of functions that do not return any value.
Summary: in this tutorial, you will learn about the TypeScript never type that contains no value.
The never type is a type that contains no values. Because of this, you cannot assign any value to a variable with
a never type.
Typically, you use the never type to represent the return type of a function that always throws an error. For
example:
26
The return type of the following function is inferred to the never type:
function reject() {
return raiseError('Rejected');
}
Code language: JavaScript (javascript)
If you have a function expression that contains an indefinite loop, its return type is also the never type. For
example:
If you see that the return type of a function is never, then you should ensure that it is not what you intended to
do.
Variables can also acquire the never type when you narrow its type by a type guard that can never be true.
For example, without the never type, the following function causes an error because not all code paths return a
value.
To make the code valid, you can return a function whose return type is the never type.
27
let neverOccur = () => {
throw new Error('Never!');
}
Code language: JavaScript (javascript)
Summary
Summary: in this tutorial, you will learn about the TypeScript union type that allows you to store a value of
one or several types in a variable.
Sometimes, you will run into a function that expects a parameter that is either a number or a string. For
example:
In this example, the add() function will calculate the sum of its parameters if they are numbers.
In case the parameters are strings, the add() function will concatenate them into a single string.
If the parameters are neither numbers nor strings, the add() function throws an error.
The problem with the parameters of the add() function is that its parameters have the any type. It means that
you can call the function with arguments that are neither numbers nor strings, the TypeScript will be fine with
it.
add(true, false);
28
Code language: JavaScript (javascript)
To resolve this, you can use the TypeScript union type. The union type allows you to combine multiple types
into one type.
A union type describes a value that can be one of several types, not just two. For example number | string |
boolean is the type of a value that can be a number, a string, or a boolean.
Back to the add() function example, you can change the types of the parameters from the any to union like this:
A TypeScript union type allows you to store a value of one or serveral types in a variable.
Summary: in this tutorial, you will learn how to define new names for types using type aliases.
Type aliases allow you to create a new name for an existing type. The following shows the syntax of the type
alias:
The following example use the type alias chars for the string type:
29
type chars = string;
let messsage: chars; // same as string type
Code language: JavaScript (javascript)
It’s useful to create type aliases for union types. For example:
Summary: in this tutorial, you will learn about the TypeScript string literal types that define a type that
accepts a specified string literal.
The string literal types allow you to define a type that accepts only one specified string literal.
The following defines a string literal type that accepts a literal string 'click':
The click is a string literal type that accepts only the string literal 'click'. If you assign the literal string click to
the click, it will be valid:
However, when you assign another string literal to the click, the TypeScript compiler will issue an error. For
example:
Error:
The string literal type is useful to limit a possible string value in a variable.
30
The string literal types can combine nicely with the union types to define a finite set of string literal values for
a variable:
If you use the string literal types in multiple places, they will be very verbose.
To avoid this, you can use the type aliases. For example:
A TypeScript string literal type defines a type that accepts specified string literal.
Use the string literal types with union types and type aliases to define types that accept a finite set of
string literals.
Summary: in this tutorial, you will learn about the Type inference in TypeScript.
Type inference describes where and how TypeScript infers types when you don’t explicitly annotate them.
When you declare a variable, you can use a type annotation to explicitly specify a type for it. For example:
However, if you initialize the counter variable to a number, TypeScript will infer the type the counter to be number.
For example:
31
let counter = 0;
Code language: JavaScript (javascript)
Likewise, when you assign a function parameter a value, TypeScript infers the type of the parameter to the
type of the default value. For example:
function setCounter(max=100) {
// ...
}
Code language: JavaScript (javascript)
To infer the type of items variable, TypeScript needs to consider the type of each element in the array.
It uses the best common type algorithm to analyze each candidate type and select the type that is compatible
with all other candidates.
In this case, TypeScript selects the number array type (number[]) as the best common type.
If you add a string to the items array, TypeScript will infer the type for the items as an array of numbers and
strings: (number | string)[]
32
let items = [0, 1, null, 'Hi'];
Code language: JavaScript (javascript)
When TypeScript cannot find the best common type, it returns the union array type. For example:
Contextual typing
TypeScript uses locations of variables to infer their types. This mechanism is known as contextual typing. For
example:
However, when you change the click event to the scroll event, TypeScript will issue an error:
Error:
TypeScript knows that the event in this case, is an instance of UIEvent, not a MouseEvent. And UIEvent does not have
the button property, therefore, TypeScript throws an error.
You will find contextual typing in may cases such as arguments to function calls, type assertions, members of
objects and array literals, return statements, and right-hand sides of assignments.
The following show the difference between type inference and type annotations:
33
TypeScript guesses the type You explicitly tell TypeScript the type
In practice, you should always use the type inference as much as possible. And you use the type annotation in
the folowing cases:
Summary
Type inference occurs when you initialize variables, set parameter default values, and determine
function return types.
TypeScript uses the best common type algorithm to select the best candidate types that are
compatible with all variables.
TypeScript also uses contextual typing to infer types of variables based on the locations of the
variables.
34
Control Flow Statements
TypeScript if else
TypeScript if statement
An if statement executes a statement based on a condition. If the condition is truthy, the if statement will
execute the statements inside its body:
if(condition) {
// if-statement
}
Code language: JavaScript (javascript)
For example, the following statement illustrates how to use the if statement to increase the counter variable if its
value is less than the value of the max constant:
console.log(counter); // 1
Code language: JavaScript (javascript)
Output:
In this example, because the counter variable starts at zero, it is less than the max constant. The expression counter
< max evaluates to true therefore the if statement executes the statement counter++.
console.log(counter); // 100
Code language: JavaScript (javascript)
35
Output:
100
In this example, the expression counter < max evaluates to false. The if statement doesn’t execute the
statement counter++. Therefore, the output is 100.
If you want to execute other statements when the condition in the if statement evaluates to false, you can use
the if...else statement:
if(condition) {
// if-statements
} else {
// else statements;
}
Code language: JavaScript (javascript)
console.log(counter);
Code language: JavaScript (javascript)
Output:
In this example, the expression counter < max evaluates to false therefore the statement in the else branch executes
that resets the counter variable to 1.
Ternary operator ?:
In practice, if you have a simple condition, you can use the ternary operator ?: rather than the if...else statement
to make code shorter like this:
console.log(counter);
Code language: JavaScript (javascript)
TypeScript if…else if…else statement
When you want to execute code based on multiple conditions, you can use the if...else if...else statement.
The if…else if…else statement can have one or more else if branches but only one else branch.
For example:
Output:
This example used the if...elseif...else statement to determine the discount based on the number of items.
If the number of items from less than or equal 5, the discount is 5%. The statement in the if branch executes,
If the number of items is less than or equal to 10, the discount is 10%. The statement in the else if branch
executes.
When the number of items is greater than 10, the discount is 15%. The statement in the else branch executes.
In this example, the assumption is that the number of items is always greater than zero. However, if the
number of items is less than zero or greater than 10, the discount is 15%.
To make the code more robust, you can use another else if instead of the else branch like this:
In this example, only when the number of items is greater than 10, the discount is 15%. The statement in the
second else if branch executes.
If the number of items is less than zero, the statement in the else branch executes.
Summary
switch ( expression ) {
case value1:
// statement 1
break;
case value2:
// statement 2
break;
case valueN:
// statement N
break;
default:
//
break;
}
Code language: JavaScript (javascript)
38
How it works:
Then, it searches for the first case clause whose expression evaluates to the same value as the value
(value1, value2, …valueN).
The switch...case statement will execute the statement in the first case clause whose value matches.
The break statement that associates with each case clause ensures that the control breaks out of
the switch...case statement once the statements in the case clause complete.
If the matching case clause doesn’t have the break statement, the program execution continues at the next
statement in the switch...case statement.
The following example shows a simple switch...case example that shows a message based on the target Id:
switch (targetId) {
case 'btnUpdate':
console.log('Update');
break;
case 'btnDelete':
console.log('Delete');
break;
case 'btnNew':
console.log('New');
break;
}
Code language: JavaScript (javascript)
Output:
39
Delete
If you have a code that is shared by multiple cases, you can group them. For example:
let day = 0;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
day = 31;
break;
case 4:
case 6:
case 9:
case 11:
day = 30;
break;
case 2:
// leap year
if (((year % 4 == 0) &&
!(year % 100 == 0))
|| (year % 400 == 0))
day = 29;
else
day = 28;
break;
default:
throw Error('Invalid month');
}
40
Output:
If the month is 1,3, 5, 7, 8, 12, the number of days is 31. If the month is 4, 6, 9, or 11, the number of days is 30.
If the month is 2 and the year is a leap year, it returns 29 days, otherwise, it returns 28 days.
TypeScript for
Summary: in this tutorial, you will learn about the TypeScript for loop statement that executes a piece of code
repeatedly.
The for loop statement creates a loop. It consists of three optional expressions separated by semicolons ( ;) and
enclosed in parentheses:
initialization:
is an expression evaluated once before the loop begins. Typically, you use the initialization to
initialize a loop counter.
condition – is an expression that is evaluated at the end of each loop iteration. If the condition is true, the
statements in the loop body execute.
expression – is an expression that is evaluated before the condition is evaluated at the end of each loop
iteration. Generally, you use the expression to update the loop counter.
All three expressions in the for loop statement are optional. It means that you can use the for loop statement
like this:
for(;;) {
// do something
}
Code language: TypeScript (typescript)
In practice, you should use a for loop if you know how many times the loop should run. If you want to stop the
loop based on a condition other than the number of times the loop executes, you should use a while loop.
41
TypeScript allows you to omit the loop body completely as follows:
However, it is rarely used in practice because it makes the code more difficult to read and maintain.
The following example uses the for loop statement to output 10 numbers from 0 to 9 to the console:
Output:
0
1
2
3
4
5
6
7
8
9
Code language: TypeScript (typescript)
How it works:
The following example shows the same output as the above example. However, the for doesn’t have
the initialization block:
let i = 0;
for (; i < 10; i++) {
42
console.log(i);
}
Code language: TypeScript (typescript)
However, you must escape the loop when a condition is met by using the if and break statements. Otherwise,
you will create an infinite loop that causes the program to executes repeatedly until it is crashed.
The following example illustrates a for loop that omits all three blocks:
let i = 0;
for (; ;) {
console.log(i);
i++;
if (i > 9) break;
}
Code language: TypeScript (typescript)
Output:
0
1
2
3
4
5
6
7
8
9
Code language: TypeScript (typescript)
How it works:
43
Summary
Use the TypeScript for statement when you want to repeatedly execute a piece of code a number of
times.
TypeScript while
Summary: in this tutorial, you will learn how to create a loop using the TypeScript while statement.
The while statement allows you to create a loop that executes a block of code as long as a condition is true.
while(condition) {
// do something
}
Code language: TypeScript (typescript)
If the condition evaluates to true, the while statement executes the code its in body surrounded by the curly
braces ({}).
When the condition evaluates to false, the execution continues with the statement after the while statement.
Since the while statement evaluates the condition before its body is executed, a while loop is also called a pretest
loop.
To break the loop immaturely based on another condition, you use the if and break statements:
while(condition) {
// do something
// ...
if(anotherCondition)
break;
}
Code language: TypeScript (typescript)
If you want to run a loop a number of times, you should use the TypeScript for statement.
44
TypeScript while statement examples
The following example uses the while statement to output a number to the console as long as it is less than 5:
let counter = 0;
Output:
0
1
2
3
4
Code language: TypeScript (typescript)
How it works:
Let’s say you have the following list element on an HTML document:
<ul id="list">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
Code language: TypeScript (typescript)
The following example shows how to use the while statement to remove all <li> element of the <ul> element:
45
while (list.firstChild) {
list.removeChild(list.firstChild);
}
Code language: TypeScript (typescript)
How it works:
Summary
Use the TypeScript while statement to create a loop that will run as long as a condition is true.
TypeScript do while
Summary: in this tutorial, you will learn how to use the do...while statement to create a loop that runs until a
condition evaluates to false.
do {
// do something
} while(condition);
Code language: TypeScript (typescript)
The do...while statement executes statements in its body surrounded by the curly braces ( {}) until
the condition is false.
The following example uses the do...while statement to output numbers from 0 to 9 to the console:
let i = 0;
46
do {
console.log(i);
i++
} while (i < 10);
Code language: TypeScript (typescript)
Output:
0
1
2
3
4
5
6
7
8
9
Code language: TypeScript (typescript)
How it works:
Summary
Use the do...while statement to create a loop that runs until a condition evaluates to false.
TypeScript break
Summary: in this tutorial, you will learn about the TypeScript break statement to terminate a loop or a switch.
The break statement allows you to terminate a loop and pass the program control over the next statement after
the loop.
let products = [
{ name: 'phone', price: 700 },
{ name: 'tablet', price: 900 },
{ name: 'laptop', price: 1200 }
47
];
Output:
How it works:
The following example returns the discount of a specified product. It uses the break statement to break out of
a switch:
let products = [
{ name: 'phone', price: 700 },
{ name: 'tablet', price: 900 },
{ name: 'laptop', price: 1200 }
];
let discount = 0;
let product = products[1];
switch (product.name) {
case 'phone':
discount = 5;
break;
case 'tablet':
discount = 10;
break;
case 'laptop':
discount = 15;
break;
}
48
console.log(`There is a ${discount}% on ${product.name}.`);
Code language: TypeScript (typescript)
Note that besides a loop or a switch, the break statement can be used to break out of a labeled statement.
However, it is rarely used in practice so that we don’t cover in this tutorial.
Summary
TypeScript continue
The continue statement skips to the end of the loop and continues the next iteration.
Output:
0
2
4
6
8
Code language: TypeScript (typescript)
In this example:
49
Then, if the current number is an odd number, skip outputting the number to the console by using
the continue statement. In case the current number is an even number, output it to the console.
The following example shows how to use the continue statement in a while loop. It returns the same result as the
above example.
index = index + 1;
if (index % 2)
continue;
console.log(index);
}
Code language: TypeScript (typescript)
Output:
0
2
4
6
8
Code language: TypeScript (typescript)
Using the TypeScript continue statement inside a do while loop
The following example demonstrates how to use the continue statement in a do...while loop. It returns the number
of even numbers from 9 to 99:
let index = 9;
let count = 0;
do {
index += 1;
if (index % 2)
continue;
count += 1;
} while (index < 99);
console.log(count); // 45
Code language: TypeScript (typescript)
50
Summary
Use the TypeScript continue statement to skip to the end of the loop and continue the next iteration.
51
Functions
TypeScript Functions
Summary: in this tutorial, you will learn about the TypeScript functions and how to use type annotations to
enforce the type checks for functions.
TypeScript functions are the building blocks of readable, maintainable, and reusable code.
Unlike JavaScript, TypeScript allows you to use type annotations in parameters and return value of a function.
When you call the add() function, the TypeScript compiler will check each argument passed to the function to
ensure that they are numbers.
In the add() function example, you can only pass numbers into it, not the values of other types.
The following code will result in an error because it passes two strings instead of two numbers into
the add() function:
Error:
error TS2345: Argument of type '"10"' is not assignable to parameter of type 'number'
Code language: JavaScript (javascript)
52
The types of the function parameters are also available within the function body for type checking.
The : number after the parentheses indicate the return type. The add() function returns a value of the number type
in this case.
When a function has a return type, TypeScript compiler checks every return statement against the return type to
ensure that the return value is compatible with it.
If a function does not return a value, you can use the void type as the return type. The void keyword indicates
that the function doesn’t return any value. For example:
The void prevents the code inside the function from returning a value and stops the calling code from
assigning the result of the function to a variable.
When you do not annotate the return type, TypeScript will try to infer an appropriate type. For example:
In this example, the TypeScript compiler tries to infer the return type of the add() function to the number type,
which is expected.
However, if a function has different branches that return different types, the TypeScript compiler may infer
the union type or any type.
Summary
Use type annotations for function parameters and return type to keep the calling code inline and
ensure the type checking within the function body.
53
Introduction to TypeScript function types
A function type has two parts: parameters and return type. When declaring a function type, you need to
specify both parts with the following syntax:
The following example shows how to declare a variable which has a function type that accepts two numbers
and returns a number:
In this example:
Note that the parameter names (x and y) are just for readability purposes. As long as the types of parameters
match, it is a valid type for the function.
Once annotating a variable with a function type, you can assign the function with the same type to the
variable.
TypeScript compiler will match the number of parameters with their types and the return type.
Also, you can declare a variable and assign a function to a variable like this:
If you assign other functions whose type doesn’t match to the add variable, TypeScript will issue an error:
In this example, we reassigned a function, whose type doesn’t match, to the add function variable.
TypeScript compiler can figure out the function type when you have the type on one side of the equation. This
form of type inference is called contextual typing. For example:
In this example, the add function will take the type (x: number, y:number) => number.
By using the type inference, you can significantly reduce the amount of code with annotations.
In JavaScript, you can call a function without passing any arguments even though the function specifies
parameters. Therefore, JaveScript supports the optional parameters by default.
In TypeScript, the compiler checks every function call and issues an error in the following cases:
The number of arguments is different from the number of parameters specified in the function.
Or the types of arguments are not compatible with the types of function parameters.
Because the compiler thoroughly checks the passing arguments, you need to annotate optional parameters to
instruct the compiler not to issue an error when you omit the arguments.
To make a function parameter optional, you use the ? after the parameter name. For example:
55
return a * b;
}
Code language: JavaScript (javascript)
How it works:
Note that if you use the expression if(c) to check if an argument is not initialized, you would find that the
empty string or zero would be treated as undefined.
The optional parameters must appear after the required parameters in the parameter list.
For example, if you make the b parameter optional, and c parameter required the TypeScript compiler will
issue an error:
Error:
JavaScript supported default parameters since ES2015 (or ES6) with the following syntax:
function name(parameter1=defaultValue1,...) {
// do something
}
56
Code language: JavaScript (javascript)
In this syntax, if you don’t pass arguments or pass the undefined into the function when calling it, the function
will take the default initialized values for the omitted parameters. For example:
console.log(applyDiscount(100)); // 95
Code language: JavaScript (javascript)
When you don’t pass the discount argument into the applyDiscount() function, the function uses a default value
which is 0.05.
Similar to JavaScript, you can use default parameters in TypeScript with the same syntax:
console.log(applyDiscount(100)); // 95
Code language: JavaScript (javascript)
Notice that you cannot include default parameters in function type definitions. The following code will result
in an error:
Error:
Like optional parameters, default parameters are also optional. It means that you can omit the default
parameters when calling the function.
57
In addition, both the default parameters and trailing default parameters share the same type. For example, the
following function:
and
Optional parameters must come after the required parameters. However, default parameters don’t need to
appear after the required parameters.
When a default parameter appears before a required parameter, you need to explicitly pass undefined to get the
default initialized value.
The following function returns the number of days in a specified month and year:
In this example, the default value of the year is the current year if you don’t pass an argument or pass the
undefined value.
The following example uses the getDay() function to get the number of days in Feb 2019:
To get the number of days in Feb of the current year, you need to pass undefined to the year parameter like
this:
Summary
Use default parameter syntax parameter:=defaultValue if you want to set the default initialized value for the
parameter.
Default parameters are optional.
To use the default initialized value of a parameter, you omit the argument when calling the function or
pass the undefined into the function.
A rest parameter allows you a function to accept zero or more arguments of the specified type. In TypeScript,
rest parameters follow these rules:
To declare a rest parameter, you prefix the parameter name with three dots and use the array type as the type
annotation:
Since the numbers parameter is a rest parameter, you can pass one or more numbers to calculate the total:
console.log(getTotal()); // 0
console.log(getTotal(10, 20)); // 30
console.log(getTotal(10, 20, 30)); // 60
Code language: JavaScript (javascript)
In this tutorial, you have learned about the TypeSript rest parameters that allow you to represent an indefinite
number of arguments as an array.
In TypeScript, function overloadings allow you to establish the relationship between the parameter types and
result types of a function.
Note that TypeScript function overloadings are different from the function overloadings supported by other
statically-typed languages such as C# and Java.
60
function addNumbers(a: number, b: number): number {
return a + b;
}
In this example:
It’s possible to use a union type to define a range of types for function parameters and results:
However, the union type doesn’t express the relationship between the parameter types and results accurately.
The add() function tells the compiler that it will accept either numbers or strings and return a number or string.
It fails to describe that the function returns a number when the parameters are numbers and return a string if
the parameters are strings.
To better describe the relationships between the types used by a function, TypeScript supports function
overloadings. For example:
In this example, we added two overloads to the add() function. The first overload tells the compiler that when
the arguments are numbers, the add() function should return a number. The second overload does the same
but for a string.
Each function overload defines a combination of types supported by the add() function. It describes the
mapping between the parameters and the result they return.
61
Now, when you call the add() function, the code editor suggests that there is an overload function available as
shown in the following picture:
When you overload a function, the number of required parameters must be the same. If an overload has more
parameters than the other, you have to make the additional parameters optional. For example:
The sum() function accepts either two or three numbers. The third parameter is optional. If you don’t make it
optional, you will get an error.
Method overloading
When a function is a property of a class, it is called a method. TypeScript also supports method overloading.
For example:
class Counter {
private current: number = 0;
count(): number;
count(target: number): number[];
count(target?: number): number | number[] {
if (target) {
let values = [];
for (let start = this.current; start <= target; start++) {
values.push(start);
}
this.current = target;
return values;
}
return ++this.current;
}
}
Code language: TypeScript (typescript)
62
The count() function can return a number or an array depending on the number of argument that you pass into
it:
Output:
1
[
1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20
]
Code language: JSON / JSON with Comments (json)
Summary
TypeScript function overloadings allow you to describe the relationship between parameter types and
results of a function.
63
Classes
TypeScript Class
Summary: in this tutorial, you will learn about the TypeScript Class.
JavaScript does not have a concept of class like other programming languages such as Java and C#. In ES5,
you can use a constructor function and prototype inheritance to create a “class”.
For example, to create a Person class that has three properties ssn, first name, and last name, you use the
following constructor function:
Next, you can define a prototype method to get the full name of the person by concatenating first name and
last name like this:
Person.prototype.getFullName = function () {
return `${this.firstName} ${this.lastName}`;
}
Code language: TypeScript (typescript)
Then, you can use the Person “class” by creating a new object:
John Doe
Code language: TypeScript (typescript)
ES6 allowed you to define a class which is simply syntactic sugar for creating constructor function and
prototypal inheritance:
class Person {
ssn;
64
firstName;
lastName;
In the class syntax, the constructor is clearly defined and placed inside the class. The following adds
the getFullName() method:
class Person {
ssn;
firstName;
lastName;
getFullName() {
return `${this.firstName} ${this.lastName}`;
}
}
Code language: TypeScript (typescript)
TypeScript class adds type annotations to the properties and methods of the class. The following shows
the Person class in TypeScript:
class Person {
ssn: string;
firstName: string;
lastName: string;
65
this.lastName = lastName;
}
getFullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}
Code language: TypeScript (typescript)
When you annotate types to properties, constructor, and method, TypeScript compiler will carry the
corresponding type checks.
For example, you cannot initialize the ssn with a number. The following code will result in an error:
Summary
Access modifiers change the visibility of the properties and methods of a class. TypeScript provides three
access modifiers:
private
protected
public
Note that TypeScript controls the access logically during compilation time, not at runtime.
The private modifier limits the visibility to the same-class only. When you add the private modifier to a property
or method, you can access that property or method within the same class. Any attempt to access private
properties or methods outside the class will result in an error at compile time.
class Person {
private ssn: string;
66
private firstName: string;
private lastName: string;
// ...
}
Code language: TypeScript (typescript)
Once the private property is in place, you can access the ssn property in the constructor or methods of
the Person class. For example:
class Person {
private ssn: string;
private firstName: string;
private lastName: string;
getFullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}
Code language: TypeScript (typescript)
The public modifier allows class properties and methods to be accessible from all locations. If you don’t
specify any access modifier for properties and methods, they will take the public modifier by default.
For example, the getFullName() method of the Person class has the public modifier. The following explicitly adds the
public modifier to the getFullName() method:
class Person {
// ...
public getFullName(): string {
return `${this.firstName} ${this.lastName}`;
}
// ...
}
Code language: TypeScript (typescript)
67
It has the same effect as if the public keyword were omitted.
The protected modifier allows properties and methods of a class to be accessible within same class and within
subclasses.
When a class (child class) inherits from another class (parent class), it is a subclass of the parent class.
The TypeScript compiler will issue an error if you attempt to access the protected properties or methods from
anywhere else.
To add the protected modifier to a property or a method, you use the protected keyword. For example:
class Person {
// other code
}
Code language: TypeScript (typescript)
The ssn property now is protected. It will be accessible within the Person class and in any class that inherits from
the Person class. You’ll learn more about inheritance here.
To make the code shorter, TypeScript allows you to both declare properties and initialize them in the construc
tor like this:
class Person {
constructor(protected ssn: string, private firstName: string, private lastName: string) {
this.ssn = ssn;
this.firstName = firstName;
this.lastName = lastName;
}
getFullName(): string {
return `${this.firstName} ${this.lastName}`;
}
}
Code language: JavaScript (javascript)
When you consider the visibility of properties and methods, it is a good practice to start with the least visible
access modifier, which is private.
68
Summary
TypeScript provides three access modifiers to class properties and methods: private, protected, and public.
The private modifier allows access within the same class.
The protected modifier allows access within the same class and subclasses.
The public modifier allows access from any location.
TypeScript readonly
Summary: in this tutorial, you will learn how to use the TypeScript readonly access modifier to mark class
properties as immutable property.
TypeScript provides the readonly modifier that allows you to mark the properties of a class immutable. The
assignment to a readonly property can only occur in one of two places:
To mark a property as immutable, you use the readonly keyword. The following shows how to declare a
readonly property in the Person class:
class Person {
readonly birthDate: Date;
constructor(birthDate: Date) {
this.birthDate = birthDate;
}
}
Code language: JavaScript (javascript)
Like other access modifiers, you can consolidate the declaration and initialization of a readonly property in the
constructor like this:
class Person {
constructor(readonly birthDate: Date) {
this.birthDate = birthDate;
69
}
}
Code language: JavaScript (javascript)
readonly const
Initialization In the declaration or in the constructor of the same class In the declaration
Summary
class Person {
public age: number;
public firstName: string;
public lastName: string;
}
Code language: TypeScript (typescript)
Suppose that you assign a value that comes from user input to the age property:
person.age = inputAge;
Code language: TypeScript (typescript)
70
The inputAge can be any number. To ensure the validity of the age, you can carry a check before assignment as
follows:
To avoid repeating the check, you can use setters and getters. The getters and setters allow you to control the
access to the properties of a class.
A getter method returns the value of the property’s value. A getter is also called an accessor.
A setter method updates the property’s value. A setter is also known as a mutator.
A getter method starts with the keyword get and a setter method starts with the keyword set.
class Person {
private _age: number;
private _firstName: string;
private _lastName: string;
How it works.
71
Third, create getter and setter methods for the _age property. In the setter method, check the validity of
the input age before assigning it to the _age property.
Notice that the call to the setter doesn’t have parentheses like a regular method. When you call person.age,
the age setter method is invoked. If you assign an invalid age value, the setter will throw an error:
person.age = 0;
Code language: TypeScript (typescript)
Error:
console.log(person.age);
Code language: TypeScript (typescript)
class Person {
private _age: number;
private _firstName: string;
private _lastName: string;
As you can see from the code, the setters are useful when you want to validate the data before assigning it to
the properties. In addition, you can perform complex logic.
class Person {
// ... other code
public get fullName() {
return `${this.firstName} ${this.lastName}`;
}
How it works.
73
The getter method returns the concatenation of the first name and last name.
The setter method accepts a string as the full name with the format: first last and assign the first part to
the first name property and second part to the last name property.
Now, you can access the fullname setter and getter like a regular class property:
console.log(person.fullName);
Code language: TypeScript (typescript)
Summary
TypeScript Inheritance
Summary: in this tutorial, you’ll learn about the TypeScript inheritance concept and how to use it to reuse the
functionality of another class.
A class can reuse the properties and methods of another class. This is called inheritance in TypeScript.
The class which inherits properties and methods is called the child class. And the class whose properties and
methods are inherited is known as the parent class. These names come from the nature that children inherit
genes from parents.
Inheritance allows you to reuse the functionality of an existing class without rewriting it.
JavaScript uses prototypal inheritance, not classical inheritance like Java or C#. ES6 introduces the class syntax
that is simply the syntactic sugar of the prototypal inheritance. TypeScript supports inheritance like ES6.
class Person {
constructor(private firstName: string, private lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName(): string {
return `${this.firstName} ${this.lastName}`;
}
describe(): string {
74
return `This is ${this.firstName} ${this.lastName}.`;
}
}
Code language: TypeScript (typescript)
To inherit a class, you use the extends keyword. For example the following Employee class inherits the Person class:
In this example, the Employee is a child class and the Person is the parent class.
Constructor
To call the constructor of the parent class in the constructor of the child class, you use the super() syntax. For
example:
Because the Employee class inherits properties and methods of the Person class, you can call
the getFullName() and describe() methods on the employee object as follows:
console.log(employee.getFullName());
console.log(employee.describe());
Code language: TypeScript (typescript)
75
Output:
John Doe
This is John Doe.
Code language: TypeScript (typescript)
Method overriding
If you want the Employee class has its own version of the describe() method, you can define it in the Employee class
like this:
super(firstName, lastName);
}
describe(): string {
return super.describe() + `I'm a ${this.jobTitle}.`;
}
}
Code language: TypeScript (typescript)
Output:
Summary
76
TypeScript Static Methods and Properties
Summary: in this tutorial, you will learn about the TypeScript static properties and methods.
Static properties
Unlike an instance property, a static property is shared among all instances of a class.
To declare a static property, you use the static keyword. To access a static property, you use
the className.propertyName syntax. For example:
class Employee {
static headcount: number = 0;
constructor(
private firstName: string,
private lastName: string,
private jobTitle: string) {
Employee.headcount++;
}
}
Code language: TypeScript (typescript)
In this example, the headcount is a static property that initialized to zero. Its value is increased by 1 whenever a
new object is created.
The following creates two Employee objects and shows the value of the headcount property. It returns two as
expected.
console.log(Employee.headcount); // 2
Code language: TypeScript (typescript)
Static methods
Similar to the static property, a static method is also shared across instances of the class. To declare a static
method, you use the static keyword before the method name. For example:
class Employee {
private static headcount: number = 0;
constructor(
private firstName: string,
private lastName: string,
77
private jobTitle: string) {
Employee.headcount++;
}
In this example:
First, change the access modifier of the headcount static property from public to private so that its value
cannot be changed outside of the class without creating a new Employee object.
Second, add the getHeadcount() static method that returns the value of the headcount static property.
console.log(Employee.getHeadcount); // 2
Code language: TypeScript (typescript)
In practice, you will find the library that contains many static properties and methods like the Math object. It
has PI, E, … static properties and abs(), round(), etc., static methods.
Summary
An abstract class is typically used to define common behaviors for derived classes to extend. Unlike a
regular class, an abstract class cannot be instantiated directly.
78
//...
}
Code language: TypeScript (typescript)
An abstract method does not contain implementation. It only defines the signature of the method without
including the method body. An abstract method must be implemented in the derived class.
In the Employee class:
Because the Employee class is abstract, you cannot create a new object from it. The following statement causes
an error:
Error:
In this FullTimeEmployee class, the salary is set in the constructor. Because the getSalary() is an abstract method of
the Employee class, the FullTimeEmployee class needs to implement this method. In this example, it just returns the
salary without any calculation.
In the Contractor class, the constructor initializes the rate and hours. The getSalary() method calculates the salary
by multiplying the rate with the hours.
The following first creates a FullTimeEmployee object and a Contractor object and then shows the compensation
statements to the console:
console.log(john.compensationStatement());
console.log(jane.compensationStatement());
Code language: TypeScript (typescript)
Output:
It’s a good practice to use abstract classes when you want to share code among some related classes.
80
Summary
Interfaces
TypeScript Interface
Summary: in this tutorial, you’ll learn about TypeScript interfaces and how to use them to enforce type
checking.
TypeScript interfaces define the contracts within your code. They also provide explicit names for type
checking.
function getFullName(person: {
firstName: string;
lastName: string
}) {
return `${person.firstName} ${person.lastName}`;
}
let person = {
firstName: 'John',
lastName: 'Doe'
};
console.log(getFullName(person));
Code language: TypeScript (typescript)
Output:
John Doe
Code language: TypeScript (typescript)
81
In this example, the TypeScript compiler checks the argument that you pass into the getFullName() function.
If the argument has two properties whose types are string, then the TypeScript compiler passes the check.
Otherwise, it’ll issue an error.
As you can see clearly from the code, the type annotation of the function argument makes the code difficult
to read.
interface Person {
firstName: string;
lastName: string;
}
Code language: CSS (css)
By convention, the interface names are in the camel case. They use a single capitalized letter to separate
words in there names. For example, Person, UserProfile, and FullName.
After defining the Person interface, you can use it as a type. And you can annotate the function parameter with
the interface name:
let john = {
firstName: 'John',
lastName: 'Doe'
};
console.log(getFullName(john));
Code language: TypeScript (typescript)
The getFullName() function will accept any argument that has two string properties. And it doesn’t have to have
exactly two string properties. See the following example:
let jane = {
firstName: 'Jane',
middleName: 'K.'
lastName: 'Doe',
82
age: 22
};
Code language: JavaScript (javascript)
Since the jane object has two string properties firstName and lastName, you can pass it into
the getFullName() function as follows:
Optional properties
An interface may have optional properties. To declare an optional property, you use the question mark ( ?) at
the end of the property name in the declaration, like this:
interface Person {
firstName: string;
middleName?: string;
lastName: string;
}
Code language: TypeScript (typescript)
In this example, the Person interface has two required properties and one optional property.
Readonly properties
If properties should be modifiable only when the object first created, you can use the readonly keyword before
the name of the property:
interface Person {
readonly ssn: string;
firstName: string;
lastName: string;
}
person.ssn = '171-28-0000';
Code language: TypeScript (typescript)
Error:
Function types
In addition to describing an object with properties, interfaces also allow you to describe function types.
To describe a function type, you assign the interface to the function signature that contains the parameter list
with types and returned types. For example:
interface StringFormat {
(str: string, isUpper: boolean): string
}
Code language: TypeScript (typescript)
The following illustrates how to declare a variable of a function type and assign it a function value of the same
type:
console.log(format('hi', true));
Code language: TypeScript (typescript)
Output:
HI
Code language: TypeScript (typescript)
Note that the parameter names don’t need to match the function signature. The following example is
equivalent to the above example:
84
let format: StringFormat;
console.log(format('hi', true));
Code language: TypeScript (typescript)
The StringFormat interface ensures that all the callers of the function that implements it pass in the required
arguments: a string and a boolean.
The following code also works perfectly fine even though the lowerCase is assigned to a function that doesn’t
have the second argument:
console.log(lowerCase('Hi', false));
Code language: TypeScript (typescript)
Class Types
If you have worked with Java or C#, you can find that the main use of the interface is to define a contract
between unrelated classes.
interface Json {
toJSON(): string
}
Code language: PHP (php)
Output:
{"firstName":"John","lastName":"Doe"}
Code language: JSON / JSON with Comments (json)
Summary
TypeScript interfaces define contracts in your code and provide explicit names for type checking.
Interfaces may have optional properties or readonly properties.
Interfaces can be used as function types.
Interfaces are typically used as class types that make a contract between unrelated classes.
Suppose that you have an interface called Mailable that contains two methods called send() and queue() as follows:
interface Mailable {
send(email: string): boolean
queue(email: string): boolean
}
Code language: TypeScript (typescript)
Now, you want to add a new method to the Mailable interface that sends an email later like this:
To avoid this, you can create a new interface that extends the Mailable interface:
interface A {
a(): void
}
interface B extends A {
b(): void
}
Code language: TypeScript (typescript)
An interface can extend multiple interfaces, creating a combination of all the interfaces. For example:
interface C {
c(): void
}
interface D extends B, C {
d(): void
}
Code language: TypeScript (typescript)
87
In this example, the interface D extends the interfaces B and C. So D has all the methods of B and C interfaces,
which are a(), b(), and c() methods.
TypeScript allows an interface to extend a class. In this case, the interface inherits the properties and methods
of the class. Also, the interface can inherit the private and protected members of the class, not just the public
members.
It means that when an interface extends a class with private or protected members, the interface can only be
implemented by that class or subclasses of that class from which the interface extends.
By doing this, you restrict the usage of the interface to only class or subclasses of the class from which the
interface extends. If you attempt to implement the interface from a class that is not a subclass of the class that
the interface inherited, you’ll get an error. For example:
class Control {
private state: boolean;
}
}
Code language: PHP (php)
Summary
88
Advanced Types
TypeScript Intersection Types
Summary: in this tutorial, you will learn about the TypeScript intersection
types.
An intersection type creates a new type by combining multiple existing types. The new type has all features of
the existing types.
Note that the union type uses the | operator that defines a variable which can hold a value of
either typeA or typeB
interface BusinessPartner {
name: string;
credit: number;
}
interface Identity {
id: number;
name: string;
}
interface Contact {
email: string;
phone: string;
}
Code language: TypeScript (typescript)
89
type Employee = Identity & Contact;
type Customer = BusinessPartner & Contact;
Code language: TypeScript (typescript)
let e: Employee = {
id: 100,
name: 'John Doe',
email: '[email protected]',
phone: '(408)-897-5684'
};
Code language: TypeScript (typescript)
let c: Customer = {
name: 'ABC Inc.',
credit: 1000000,
email: '[email protected]',
phone: '(408)-897-5735'
};
Code language: TypeScript (typescript)
Later, if you want to implement employee sales, you can create a new intersection type that contains all
properties of Identity, Contact, and BusinessPartner types:
let e: Employee = {
id: 100,
name: 'John Doe',
email: '[email protected]',
phone: '(408)-897-5684',
credit: 1000
};
Code language: TypeScript (typescript)
Notice both BusinessPartner and Identity have the property name with the same type. If they do not, then you will
have an error.
Type Order
When you intersect types, the order of the types doesn’t matter. For example:
90
type typeAB = typeA & typeB;
type typeBA = typeB & typeA;
Code language: TypeScript (typescript)
Summary
An intersection type combines two or more types to create a new type that has all properties of the
existing types.
The type order is not important when you combine types.
Type Guards allow you to narrow down the type of a variable within a conditional block.
typeof
throw new Error('Invalid arguments. Both arguments must be either numbers or strings.');
}
Code language: TypeScript (typescript)
How it works:
91
Finally, throw an error if arguments are neither numbers nor strings.
In this example, TypeScript knows the usage of the typeof operator in the conditional blocks. Inside the
following if block, TypeScript realizes that a and b are numbers.
Similarly, in the following if block, TypeScript treats a and b as strings, therefore, you can concatenate them
into one:
instanceof
Similar to the typeof operator, TypeScript is also aware of the usage of the instanceof operator. For example:
class Customer {
isCreditAllowed(): boolean {
// ...
return true;
}
}
class Supplier {
isInShortList(): boolean {
// ...
return true;
}
}
return message;
92
}
Code language: TypeScript (typescript)
How it works:
Inside the following if block, TypeScript knows that the partner is an instance of the Customer type due to
the instanceof operator:
Likewise, TypeScript knows that the partner is an instance of Supplier inside the following if block:
When an if narrows out one type, TypeScript knows that within the else it is not that type but the other. For
example:
in
The in operator carries a safe check for the existence of a property on an object. You can also use it as a type
guard. For example:
User-defined type guards allow you to define a type guard or help TypeScript infer a type when you use a
function.
A user-defined type guard function is a function that simply returns arg is aType. For example:
In this example, the isCustomer() is a user-defined type guard function. Now you can use it in as follows:
return message;
}
Code language: TypeScript (typescript)
Summary
Type guards narrow down the type of a variable within a conditional block.
Use the typeof and instanceof operators to implement type guards in the conditional blocks
Type Casting
Summary: in this tutorial, you will learn about type castings in TypeScript, which allow you to convert a
variable from one type to another type.
JavaScript doesn’t have a concept of type casting because variables have dynamic types. However, every
variable in TypeScript has a type. Type castings allow you to convert a variable from one type to another.
94
In TypeScript, you can use the as keyword or <> operator for type castings.
Since the returned type of the document.querySelector() method is the Element type, the following code causes a
compiler error:
console.log(input.value);
Code language: TypeScript (typescript)
The reason is that the value property doesn’t exist in the Element type. It only exists on
the HTMLInputElement type.
To resolve this, you can use type casting that cast the Element to HTMLInputElement by using the as keyword like
this:
Now, the input variable has the type HTMLInputElement. So accessing its value property won’t cause any error. The
following code works:
console.log(input.value);
Code language: TypeScript (typescript)
Another way to cast the Element to HTMLInputElement is when you access the property as follows:
Note that the HTMLInputElement type extends the HTMLElement type that extends to the Element type. When you
cast the HTMLElement to HTMLInputElement, this type casting is also known as a down casting.
In this example, the el variable has the HTMLElement type. And you can assign it an instance
of HTMLInputElement type because the HTMLInputElement type is an subclass of the HTMLElement type.
95
The syntax for converting a variable from typeA to typeB is as follows:
let a: typeA;
let b = a as typeB;
Code language: TypeScript (typescript)
Besides the as keyword, you can use the <> operator to carry a type casting. For example:
console.log(input.value);
Code language: TypeScript (typescript)
let a: typeA;
let b = <typeB>a;
Code language: TypeScript (typescript)
Summary
Type casting allows you to convert a variable from one type to another.
Use the as keyword or <> operator for type castings.
Type Assertions
Summary: in this tutorial, you will learn about type assertions in TypeScript.
Type assertions instruct the TypeScript compiler to treat a value as a specified type. It uses the as keyword to
do so:
expression as targetType
Code language: TypeScript (typescript)
A type assertion is also known as type narrowing. It allows you to narrow a type from a union type. Let’s see
the following simple function:
96
The getNetPrice() function accepts price, discount, and format arguments and returns a value of the union type number |
string.
If the format is true, the getNetPrice() returns a formatted net price as a string. Otherwise, it returns the net price as
a number.
The following uses the as keyword to instruct the compiler that the value assigned to the netPrice is a string:
Output:
$95
Code language: TypeScript (typescript)
Similarly, the following uses the as keyword to instruct the compiler that the returned value of
the getNetPrice() function is a number.
Output:
95
Code language: TypeScript (typescript)
Note that a type assertion does not carry any type casting. It only tells the compiler which type it should apply
to a value for the type checking purposes.
You can also uses the angle bracket syntax <> to assert a type, like this:
<targetType> value
Code language: TypeScript (typescript)
For example:
Note that you cannot use angle bracket syntax <> with some libraries such as React. For this reason, you
should use the as keyword for type assertions.
97
Summary
98
Generics
TypeScript Generics
Summary: in this tutorial, you’ll learn about TypeScript generics that allow you to use types as formal
parameters.
TypeScript generics allow you to write the reusable and generalized form of functions, classes, and interfaces.
In this tutorial, you’re focusing on developing generic functions.
Suppose you need to develop a function that returns a random element in an array of numbers.
To find the random index of an array, we used the Math.random() that returns a random number between 0 and
1, multiplied it with the length of the array, and applied the Math.floor() on the result.
Assuming that you need to get a random element from an array of strings. This time, you may come up with a
new function:
99
let randomIndex = Math.floor(Math.random() * items.length);
return items[randomIndex];
}
Code language: TypeScript (typescript)
Later you may need to get a random element in an array of objects. Creating a new function every time you
want to get a random element from a new array type is not scalable.
One solution for this issue is to set the type of the array argument as any[]. By doing this, you need to write just
one function that works with an array of any type.
console.log(getRandomAnyElement(numbers));
console.log(getRandomAnyElement(colors));
Code language: TypeScript (typescript)
It doesn’t allow you to enforce the type of the returned element. In other words, it isn’t type-safe.
A better solution to avoid code duplication while preserving the type is to use generics.
The following shows a generic function that returns the random element from an array of type T:
100
function getRandomElement<T>(items: T[]): T {
let randomIndex = Math.floor(Math.random() * items.length);
return items[randomIndex];
}
Code language: TypeScript (typescript)
This function uses type variable T. The T allows you to capture the type that is provided at the time of calling
the function. Also, the function uses the T type variable as its return type.
This getRandomElement() function is generic because it can work with any data type including string, number,
objects,…
By convention, we use the letter T as the type variable. However, you can freely use other letters such
as A, B C, …
In practice, you’ll use type inference for the argument. It means that you let the TypeScript compiler set the
value of T automatically based on the type of argument that you pass into, like this:
In this example, we didn’t pass the number type to the getRandomElement() explicitly. The compiler just looks at the
argument and sets T to its type.
Now, the getRandomElement() function is also type-safe. For example, if you assign the returned value to a string
variable, you’ll get an error:
101
Generic functions with multiple types
The following illustrates how to develop a generic function with two type variables U and V:
The merge() function merges two objects with the type U and V. It combines the properties of the two objects
into a single object.
Type inference infers the returned value of the merge() function as an intersection type of U and V, which is U &
V
The following illustrates how to use the merge() function that merges two objects:
console.log(result);
Code language: JavaScript (javascript)
Output:
Summary
Use TypeScript generics to develop reusable, generalized, and type-safe functions, interfaces, and
classes.
102
TypeScript Generic Constraints
Summary: in this tutorial, you’ll learn about the generic constraints in TypeScript.
console.log(result);
Code language: TypeScript (typescript)
Output:
The merge() function expects two objects. However, it doesn’t prevent you from passing a non-object like this:
console.log(person);
Code language: TypeScript (typescript)
Output:
{ name: 'John' }
Code language: TypeScript (typescript)
103
TypeScript doesn’t issue any error.
Instead of working with all types, you may want to add a constraint to the merge() function so that it works with
objects only.
To do this, you need to list out the requirement as a constraint on what U and V types can be.
Because the merge() function is now constrained, it will no longer work with all types. Instead, it works with
the object type only.
Error:
TypeScript allows you to declare a type parameter constrained by another type parameter.
The following prop() function accepts an object and a property name. It returns the value of the property.
104
To fix this error, you add a constraint to K to ensure that it is a key of T as follows:
If you pass into the prop function a property name that exists on the obj, the compiler won’t complain. For
example:
Output:
John
Code language: TypeScript (typescript)
However, if you pass a key that doesn’t exist on the first argument, the compiler will issue an error:
Error:
Summary
A generic class has a generic type parameter list in an angle brackets <> that follows the name of the class:
class className<T>{
//...
}
Code language: TypeScript (typescript)
105
TypeScript allows you to have multiple generic types in the type parameter list. For example:
class className<K,T>{
//...
}
Code language: TypeScript (typescript)
Placing the type parameter on the class allows you to develop methods and properties that work with the
same type.
A stack is a data structure that works on the last-in-first-out (or LIFO) principle. It means that the first element
you place into the stack is the last element you can get from the stack.
Typically, a stack has a size. By default, it is empty. The stack has two main operations:
class Stack<T> {
private elements: T[] = [];
Now, you can use the randBetween() function to generate random numbers for pushing into the numbers stack:
while (!numbers.isFull()) {
let n = randBetween(1, 10);
console.log(`Push ${n} into the stack.`)
numbers.push(n);
}
Code language: TypeScript (typescript)
Output:
The following shows how to pop elements from the stack until it is empty:
while (!numbers.isEmpty()) {
let n = numbers.pop();
console.log(`Pop ${n} from the stack.`);
}
107
Code language: TypeScript (typescript)
Output:
let words = 'The quick brown fox jumps over the lazy dog'.split(' ');
How it works:
In this tutorial, you have learned how to develop generic classes in TypeScript.
Like classes, interfaces also can be generic. A generic interface has generic type parameter list in an angle
brackets <> following the name of the interface:
interface interfaceName<T> {
// ...
108
}
Code language: TypeScript (typescript)
The type parameter list can have one or multiple types. For example:
interface interfaceName<U,V> {
// ...
}
Code language: TypeScript (typescript)
The following show how to declare a generic interface that consists of two members key and value with the
corresponding types K and V:
Now, you can use the Pair interface for defining any key/value pair with any type. For example:
console.log(month);
Code language: TypeScript (typescript)
In this example, we declare a month key-value pair whose key is a string and value is a number.
The following declares a generic interface with two methods add() and remove():
interface Collection<T> {
add(o: T): void;
remove(o: T): void;
}
Code language: TypeScript (typescript)
109
And this List<T> generic class implements the Collection<T> generic interface:
From the List<T> class, you can create a list of values of the various type e.g., numbers, or strings.
For example, the following shows how to use the List<T> generic class to create a list of numbers:
interface Options<T> {
[name: string]: T
}
In this tutorial, you have learned about the TypeScript generic interfaces.
110
Modules
TypeScript Modules
Summary: in this tutorial, you will learn about the TypeScript modules and how to use the to structure your
code.
Since ES6, JavaScript started supporting modules as the native part of the language. TypeScript shares the
same module concept with JavaScript.
A TypeScript module can contain both declarations and code. A module executes within its own scope, not in
the global scope. It means that when you declare variables, functions, classes, interfaces, etc., in a module,
they are not visible outside the module unless you explicitly export them using export statement.
On the other hand, if you want to access variables, functions, classes, etc., from a module, you need to import
them using the import statement.
Like ES6, when TypeScript file contains a top-level import or export, it is treated as a module.
Export statements
Another way to export a declaration from a module is to use the export statement. For example:
interface Validator {
isValid(s: string): boolean
}
111
export { Validator };
Code language: TypeScript (typescript)
TypeScript also allows you to rename declarations for module consumers, like this:
interface Validator {
isValid(s: string): boolean
}
To consume a module, you use the import statement. The following creates a new module EmailValidator.ts that
uses the Validator.ts module:
export { EmailValidator };
Code language: TypeScript (typescript)
export { EmailValidator };
112
Code language: TypeScript (typescript)
console.log(result);
Code language: TypeScript (typescript)
Output:
true
Code language: TypeScript (typescript)
Importing types
Note that TypeScript has supported the import type statement since version 3.8. Prior to TypeScript 3.8, you
need to use the import statement instead:
Re-exports
export { ZipCodeValidator };
Code language: TypeScript (typescript)
You can wrap the EmailValidator and ZipCodeValidator modules in a new module by combining all their exports
using the following syntax:
Default Exports
TypeScript allows each module to have one default export. To mark an export as a default export, you use
the default keyword.
The following shows how to use the default export from the ZipCodeValidator in the App.ts file:
console.log(result);
Code language: TypeScript (typescript)
Output:
true
Code language: TypeScript (typescript)
Summary
TypeScript shares the same module concept with ES6 module. A module can contain both declarations
and code.
In a module, variables, functions, classes, interfaces, etc., executes on its own scope, not the global
scope.
Use export statement to export variables, functions, classes, interfaces, type, etc., from a module.
Use import statement to access exports from other modules.
115
TypeScript in Node.js
Node.js Typescript: How to Automate the Development Workflow
Summary: in this tutorial, you’ll learn how to automate the development workflow for using TypeScript in a
Node.js project.
This tutorial assumes that you have the node.js and tsc module installed on your system.
Once the TypeScript compiler compiles the source TypeScript files, it will store the output files in
the build directory.
From the Terminal on macOS and Linux or Command Prompt on Windows, run the following command in
the nodets directory to create the tsconfig.json file:
tsc --init
The tsconfig.json file indicates that the directory (nodets) is the root of the TypeScript project.
When you compile the TypeScript files, TypeScript compiler will use the options in the tsconfig.json to compile
the project.
116
Now, you can open the tsconfig.json file. There are many options. In this tutorial, you’ll focus on these two
options:
These options are commented by default. And you’ll need to uncomment ( remove the // at the beginning of
the line) and change them as follows:
For the outDir option:
"outDir": "./build"
Code language: JavaScript (javascript)
"rootDir": "./src"
Code language: JavaScript (javascript)
To verify the new configuration, you can create a new file called app.ts under the ./src directory and place the
following code:
console.log('Node.js TypeScript');
Code language: JavaScript (javascript)
And then run the following command to execute the TypeScript compiler. It’ll compile all the files stored in
the src directory:
tsc
To run the app.js, you navigate to the build directory and execute the following command:
117
node app.js
Code language: CSS (css)
Node.js TypeScript
Code language: CSS (css)
Every time when you change the TypeScript code, you need to:
This is time-consuming.
Luckly, you can automate the whole process using some Node.js modules.
The nodemon module allows you to automatically restart the application when you change the JavaScript source
code.
First, execute the npm init command from the root directory of the project:
Note that the -g flag will instruct npm to install these two modules globally. This allows you to use them in
other projects.
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
...
Code language: JavaScript (javascript)
118
After that, change the scripts option to the following:
...
"scripts": {
"start:build": "tsc -w",
"start:run": "nodemon build/app.js",
"start": "concurrently npm:start:*"
},
...
Code language: JavaScript (javascript)
This "start:build": "tsc -w" will watch for the changes in the ./src directory and compile them automatically.
This "start:run": "nodemon build/app.js" will automatically run the app.js in the ./build directory whenever the new file is
generated.
This "start": "concurrently npm:start:*" runs all the commands that start with npm:start:*, which executes
both start:build and start:run commands above.
Since the app.js will be the entry point for the Node.js program, you also need to change the following option
in the package.json file to app.js:
From:
"main": "index.js"
Code language: JavaScript (javascript)
To:
"main": "app.js"
Code language: JavaScript (javascript)
npm start
To verify the configuration, you change some code in the app.ts. And you’ll see the output in the console.
In this tutorial, you’ve learned how to set up a development workflow for using TypeScript in Node.js projects.
119