9 min read

JavaScript, being a flexible scripting language along with its dynamic type system, can become harder to maintain, the more a project scales up and as the team’s staff changes. There are many tools and languages that can assist with this situation, one of which is TypeScript.

This article is an excerpt from a book written by Tamir Dresher, Amir Zuker, and Shay Friedman titled Hands-On Full-Stack Web Development with ASP.NET Core. In this book, you will learn how to build web applications using Angular, React, and Vue.

Back in the day when JavaScript ES5 was the active version, writing JavaScript code that adhered to encapsulation and modularity was not a trivial task. Things such as prototypes, namespaces, and self-executing functions could certainly improve your code; unfortunately, many JavaScript developers did not invest the necessary effort to improve the manageability of their code using those constructs.

Consequently, new technologies surfaced to help with this matter; a popular example relevant at that time was CoffeeScript. Then, JavaScript ES6 was released. ES6, with its great added features, such as modules, classes, and more specific variable scoping, basically overturned CoffeeScript and similar alternatives at that time.

Evidently, JavaScript is still missing a key feature, and that is type information. JavaScript’s dynamic type system is a strong feature at times; unfortunately, the manageability and reusability of existing code suffers due to this fact. For that key purpose, every large-scale project should examine the use of tools that compensate the situation; those leading the field now are TypeScript and Flow.


TypeScript, an open source scripting language, is developed and maintained by Microsoft. Its killer feature is bringing static typing to JavaScript-based systems and allowing you to annotate the code with type information. Additionally, it supports augmenting existing JavaScript code with external type information, similar to the header files pattern, as it’s commonly known in C++.

TypeScript is a superset of JavaScript, that meaning it has seamless integration with JavaScript, and makes JavaScript developers feel right at home. Being a JavaScript developer makes you a TypeScript developer as well since JavaScript code is actually valid TypeScript. Importantly, this makes the gradual upgrade of existing JavaScript code fairly easy.

Another example of how great TypeScript is is the fact that Angular, a framework built by Google, adopts it extensively, and is actually implemented in TypeScript internally.

The TypeScript compiler

TypeScript is a superset of JavaScript, yet browsers and other platforms don’t recognize it, nor are they able to execute it. For that purpose, TypeScript is processed by the TypeScript compiler, which transpiles your TypeScript code to JavaScript. Then, you can run the transpiled code basically everywhere JavaScript is supported.

The tsc is available as an npm package that you can install globally. Open your favorite terminal and install it using the following command:

npm install -g typescript

Afterward, you can use the command tsc to execute the tsc:

TypeScript files have a .ts file extension; this is where you write your TypeScript code. When needed, you use the TypeScript compiler to transpile your TypeScript code, which creates the JavaScript implementation of the code; you do that by executing the following command:

 tsc 

Types in Typescript

One of the key features of TypeScript is bringing static typing to JavaScript. In TypeScript, you annotate your code with type information; every declaration can be defined with its associated typing.

In the declaration, you do that by adding a colon following the type. For example, the following statement defines a variable of type number:

const productsCount: number;

Annotating your code with type information enables validation. The TypeScript compiler should throw errors if you try to do anything that is not supported by the specified type, thus productivity and discoverability benefit substantially through type safety. Additionally, with proper tooling support, you get IntelliSense support and automatic code completion.

TypeScript supports a handful of types to reflect most constructs in JavaScript. We will cover these next, starting with basic types.

Basic types

TypeScript supports a handful of built-in types; the following are examples of the most common ones:

const fullName: string = "John Doe";
const age: number = 6;
const isDone: boolean = false;
const d: Date = new Date();
const canBeAnything: any = 6;

As you can see, TypeScript supports basic primitive types such as string, number, boolean, and date.

Another thing to notice is the type any. The any type is a valid TypeScript type that indicates that the declaration can be of any given type and all operations on it should be allowed and considered safe.

Arrays

TypeScript arrays can be written in one of two ways. You can specify the item type followed by square brackets or you can use the generic Array type as follows:

const list: number[] = [1, 2, 3];
const list: Array = [1, 2, 3];

Enums

Enums allow you to specify named values that correspond to numeric or string values. If you don’t manually set the associated corresponding value, the named values in the enum are numbered, starting at 0 by default. Enums are extremely useful, and are commonly used to represent a set of predefined options or lookup values.

In TypeScript, you define enums by using the enum keyword as follows:

enum Color {Red, Green, Blue}
const c: Color = Color.Red;

Objects

In JavaScript, objects contain key/value pairs that form the shape of the object. TypeScript supports object types as well, very similar to how you write plain JavaScript objects.

Consider the following plain JavaScript object:

const obj = {
  x: 5,
  y: 6
}

In the preceding code, obj is a plain object defined with two keys, x and y, both with number values.

To define an object type in TypeScript, you use a similar format — curly braces to represent an object, inside the keys, and their type information:

{ x:number, y:number }

Together, this is how you associate a type to an object:

const obj: { x:number, y:number } = {
  x: 5,
  y: 6
}

In the preceding code, the obj object is initialized the same as before, only now along with its type information, which is marked in bold.

Functions

Functions have type information as well. Functions are comprised of parameters and a return value:

function buildName(firstName: string, lastName: string): string {
    return firstName + " " + lastName;
}

Each parameter is annotated with its type, and then the return value’s type is added at the end of the function signature.

Unlike JavaScript, TypeScript enforces calls to functions to adhere to the defined signature. For example, if you try to call the function with anything other than two string parameters, the TypeScript compiler will not allow it.

You can define more flexible function signatures if you like. TypeScript supports defining optional parameters by using the question mark symbol, ?:

function buildName(firstName: string, lastName: string, title?: string): string {
    return title + " " + firstName + " " + lastName;
}

const name = buildName(‘John’, ‘Doe’); // valid call

The preceding function can now be called with either 2 or 3 string parameters.

Everything in JavaScript is still supported, of course. You can still use ES6 default parameter values and rest parameters as well.

Type inference

Until now, the illustrated code included the type information in the same statement where the actual value assignment took place. TypeScript supports type inference, meaning that it tries to resolve the relevant type information if you don’t specify any.

Let’s look at some examples:

const count = 2;

In the preceding simple example, TypeScript is smart enough to realize that the type of count is a number without you having to explicitly specify that:

function sum(x1: number, x2: number) {
            return x1 + x2;
}

const mySum = sum(1, 2);

The preceding example demonstrates the power of type inference in TypeScript. If you pay close attention, the code doesn’t specify the return value type of the sum function. TypeScript evaluates the code and determines that the return type is number in this case. As a result, the type of the variable mySum is also a number.

Type inference is an extremely useful feature since it saves us the incredible time that would be otherwise spent in adding endless type information.

Type casting

Having the code statically typed leads to type safety. TypeScript does not let you perform actions that are not considered safe and supported.

In the following example, the loadProducts function is defined with a return value of type any, thus the type of products is inferred as any:

function loadProducts(): any {
    return [{name: 'Book1'}, {name: 'Book2'}];
}

const products = loadProducts(); // products is of type ‘any’

In some cases, you may actually know the expected type. You can instruct TypeScript of the type by using a cast. Typecasting in TypeScript is supported by using the as an operator or the use of angle brackets, as follows:

const products = loadProducts() as {name: string}[];
const products = loadProducts();

Using the preceding cast, you have full support and recognition by TypeScript that products is now an array of objects with a name key.

Type aliasing

TypeScript supports defining new types via type aliases. You can use type aliases to reuse type information in multiple declarations, for example:

type person = {name: string};
let employee: person;
let contact: person;

Given the preceding example, the code defines a type alias named person as an object with a name key of type string. Afterwards, the rest of the code can reference this type where needed.

Type aliases are somewhat similar to interfaces (covered next), but can name primitives, unions, and tuples. Unlike interfaces, type aliases cannot be extended or implemented from, and so interfaces are generally preferred.

Unions and intersections allow you to construct a type from multiple existing types, while tuples express arrays with a fixed number of known elements. You can read more about these at https://www.typescriptlang.org/docs/handbook/basic-types.html and
https://www.typescriptlang.org/docs/handbook/advanced-types.html.

TypeScript is one of the most popular scripting languages in respect to JavaScript-based code bases. At its very core, it brings static typing and assists tremendously with maintainability and productivity.

In this article, we covered TypeScript types. TypeScript advances at a steady pace and shows great promise for using it in large projects. It has more features that weren’t addressed in this tutorial, such as generics, mapped types, abstract classes, project references, and much more that will help you for ASP.NET core development.

To know more about interfaces and compilers of TypeScript, check out the book Hands-On Full-Stack Web Development with ASP.NET Core.

Read next

Typescript 3.3 is finally released!

Future of ESLint support in TypeScript

Introducing ReX.js v1.0.0 a companion library for RegEx written in TypeScript