TypeScript Tutorial: What is, Interface, Enum, Array

โšก Smart Summary

TypeScript is a strongly typed superset of JavaScript that compiles to plain JavaScript and adds classes, interfaces, enums, modules, and namespaces. This article covers installation, variables, types, arrays, classes, access modifiers, interfaces, functions, enums, modules, and ambient declarations.

  • ๐Ÿงฌ Language Relationship: Every valid JavaScript program is valid TypeScript, and the compiler emits plain JavaScript for any target version.
  • ๐Ÿ”’ Static Typing: A variable keeps the type given at declaration, so a mismatch is reported at compile time rather than at runtime.
  • ๐Ÿงฑ Object Orientation: Classes, inheritance, and public, private, and protected modifiers bring familiar structure to browser code.
  • ๐Ÿ“ Interfaces: An interface defines a contract of properties and methods that a variable, function, or class must satisfy.
  • ๐Ÿ”ข Enums: Named constant sets compile into self invoked functions, since JavaScript has no native enum type.
  • ๐Ÿ“ฆ Modules: Export and import keep declarations local to a file and prevent global name collisions.
  • ๐Ÿ”Œ Ambient Declarations: A .d.ts file describes a third party JavaScript library so type checking applies without rewriting it.

TypeScript Tutorial

What is TypeScript?

TypeScript is a superset of JavaScript. TypeScript is an object-oriented programming language that supports classes, interfaces, and more. It is an open-source language developed by Microsoft which statically compiles the code to JavaScript. It can easily run in a browser or in Nodejs.

All the latest features released for ECMAScript are supported in TypeScript, and in addition TypeScript has its own object-oriented features such as interfaces, ambient declarations, and class inheritance, which help in developing a large application that would otherwise be difficult to build in JavaScript.

The relationship is one directional. Every valid JavaScript file is already valid TypeScript, but the reverse is not true, because type annotations exist only in TypeScript and are erased during compilation.

Why use TypeScript?

Here are the important benefits of using TypeScript:

  • Big and complex projects in JavaScript are difficult to code and maintain.
  • TypeScript helps a lot with code organisation, and removes most errors during compilation rather than at runtime.
  • TypeScript supports JS libraries and API documentation.
  • It is an optionally typed scripting language, so types can be adopted gradually.
  • TypeScript code can be converted into plain JavaScript code for any browser target.
  • It gives better code structuring and object-oriented programming techniques.
  • It allows better development time tool support, including autocompletion and safe refactoring.
  • It can extend the language beyond the standard, with features such as decorators.

The single largest practical gain is editor support. Because the compiler knows the shape of every value, an editor can rename a property across an entire project and report each place that no longer matches.

TypeScript History

Let us see the important landmarks from the history of TypeScript:

  • After two years of internal development at Microsoft, TypeScript 0.9 was released in 2013.
  • TypeScript 1.0, with additional support for generics, was released at Build 2014.
  • In July 2014, a new TypeScript compiler arrived which was five times faster than the previous version.
  • In July 2015, support was added for ES6 modules, the namespace keyword, forโ€ฆof, and decorators.
  • In November 2016, mapped types, key and lookup types, and object rest and spread were added.
  • On March 27, 2018, conditional types and improved keyof with intersection types were added.
  • TypeScript 5.0, released in March 2023, modernised decorators and reduced package size.
  • TypeScript 6.0 arrived in March 2026 as the final release built on the JavaScript codebase.
  • TypeScript 7.0 moves the compiler to a native Go implementation, which Microsoft reports as roughly ten times faster than 6.0.

Who uses TypeScript?

TypeScript is no longer a niche choice. It underpins several of the most widely used front-end and back-end tools, and the list below shows where a beginner is most likely to meet it.

  • Angular: The Angular framework is written in TypeScript, and application code is expected to be written in it as well.
  • React and Vue projects: Both ecosystems ship official TypeScript templates, and most modern starters enable it by default.
  • Node.js back ends: Server frameworks such as NestJS are built around TypeScript classes and decorators.
  • Editor tooling: Visual Studio Code is itself a large TypeScript codebase, which is why its language support is so complete.
  • Large enterprise front ends: Teams working with many contributors adopt it to catch integration errors before deployment.

How to Download and Install TypeScript

Here is the step by step process to download and install TypeScript:

Step 1) Download and Install Nodejs

Go to the official site of Nodejs, https://nodejs.org/en/download/, and download and install Nodejs for your operating system. Detailed instructions are available in the guide on how to download and install Node.js.

Step 2) Check Nodejs and npm version

To check whether Nodejs and npm are installed, check the version in your command prompt.

D:\typeproject>node --version
v22.14.0

D:\typeproject>npm --version
10.9.2

Any current Node LTS release works. TypeScript itself only requires a supported Node version to run the compiler.

Step 3) TypeScript Installation

Create your project directory typeproject\ and run npm init, as shown in the command below:

npm init

Step 4) Start the Installation

This creates package.json, which will store the dependencies for our project.

Once done, install TypeScript as follows:

npm -g install typescript

The above command will take care of installing TypeScript. Adding “-g” to npm install will install TypeScript globally. The advantage of using -g is that you will be able to use the TypeScript tsc command from any directory, as it is installed globally. In case you do not want to install TypeScript globally, use the command below:

npm install --save-dev typescript

Create a src\ folder in your project directory, and inside src\ create the TypeScript file test.ts and write your code.

Example : test.ts

function add(x:number, y:number) {
	return x+y;
}

let sum = add(5,10);
console.log(sum);

Compile TypeScript code to Javascript

To compile the above code use the following command.

If TypeScript is installed globally use the command below:

tsc test.ts

If TypeScript is installed locally in your project you need to use the path of TypeScript from node_modules, as shown, or run it through npx:

node_modules\typescript\bin\tsc test.ts

OR

npx tsc test.ts

The above command will create a test.js file which will have the code compiled to JavaScript.

Example : test.js

function add(x, y) {
    return x + y;
}
var sum = add(5, 10);
console.log(sum);

Execute Javascript using Nodejs

Now we will execute test.js in Nodejs as follows:

D:\typeproject\src>node test.js
15

The value passed to console.log is displayed when test.js runs.

Execute JavaScript in Browser

Example:

<html>
<head></head>
<body>
<script type="text/javascript" src="test.js"></script>
</body>
</html>

Execute Javascript using Nodejs

Compile TypeScript code to Javascript using EcmaScript version

TypeScript supports all the ECMAScript features released, and developers can use them while coding. But not all new features are supported on older browsers, so you may need to compile to an older version of ECMAScript. TypeScript provides compiler options which do exactly that.

Example : test.ts

var addnumbers = (a, b) => {
    return a+b;
}

addnumbers(10, 20);

To compile to the ES version of your choice, you can use the target or t option in your command as follows:

tsc --target ES6  test.ts

OR

tsc -t ES6 test.ts

By default, the target is ES3 for the classic compiler. In case you want to change it, you can use the command above.

At present we will use ES6 as the target:

tsc --target ES6  test.ts

test.ts to test.js

var addnumbers = (a, b) => {
    return a+b;
}

addnumbers(10, 20);

The code remains as it is, because the arrow function you have used is an ES6 feature and is unchanged when compiled to ES6.

By default the target is ES3, so without a target you get test.js as:

var addnumbers = function (a, b) {
    return a + b;
};
addnumbers(10, 20);

So here, the fat arrow is changed to a normal anonymous function.

๐Ÿ’ก Tip: Rather than passing options on the command line each time, run tsc --init to generate a tsconfig.json file. The compiler then reads target, outDir, and strict settings from that file for the whole project.

Variables in TypeScript

Variables are used to store values, and the value can be a string, number, Boolean, or an expression. When it comes to variables in TypeScript, they are similar to JavaScript. So let us learn to declare and assign a value to variables in TypeScript.

Variables cannot be used in code without being defined. To declare a variable you can use

var keyword,

let keyword

const keyword

Working with variables in TypeScript is similar to JavaScript, and users familiar with JavaScript will find it very easy. In modern code, let and const are preferred over var, because their block scope prevents a whole class of bugs.

Declaring variables using var

Syntax:

var firstname = "Roy";

Let us take a look at a few TypeScript examples to understand the working of the var keyword and also the scope of variables declared using the var keyword.

Example 1:

var k = 1; // variable k will have a global scope

function test() {
    var c = 1; // variable c is local and accessible only inside function test
    return k++;
}

test(); // output as 1
test(); // output as 2
alert(c); // will throw error, Uncaught ReferenceError: c is not defined

Example 2:

var t = 0; // variable t is declared in global scope
function test() {
    var t = 10; // t is redeclared inside the function, so changes stay local
    return t;
}
test(); // will return 10
console.log(t); // will console 0

Example 3:

var i = 0;
function test() {
    if (i > 0) {
      var t = 1;
    }
    return t;
}

test(); // returns undefined. The if block did not run, yet t is still declared
        // because var declarations are hoisted to the whole function.
i++;    // value of i is incremented
test(); // since i > 0 the if block runs and the value returned is 1

Declaring variables using let

The TypeScript syntax for let is as given below:

Syntax:

let name = "Roy";

The working of the let variable is almost the same as var, but with one important difference, which the example below demonstrates.

Example:

let i = 1;
function test() {
    if (i > 0) {
	  let t = 1;
    }
    return t;
}

test(); // throws an error: Cannot find name 't'

The above TypeScript example throws an error, but the same code would have worked with the var keyword. Variables declared using let are available only within the block in which they are declared. In this example, t exists only inside the if block, not in the whole function.

The same applies inside any function, for loop, while loop, or switch block. A let variable is available only inside that block, and referencing it outside throws an error. This is the main difference between var and let.

Declaring variables using const

Const means constant variables. They are similar to let variables, with the difference that once a value is assigned it cannot be changed. A const declaration must therefore be initialised on the same line.

Syntax:

const name = "Roy";

Example:

const age = "25";
age = "30"; // error: Cannot assign to 'age' because it is a constant

const total; // error: 'const' declarations must be initialized

So use const whenever you know the value assigned will not be reassigned. Note that const prevents reassignment of the binding, not modification of an object it points to.

Types in TypeScript

TypeScript is a strongly typed language, whereas JavaScript is not. A variable whose value is defined as a string can be changed to a number without any issue in JavaScript. The same is not tolerated in TypeScript. In TypeScript, the type of a variable is defined at the start, and throughout execution it must keep that type. Any change leads to a compile-time error during compilation to JavaScript.

The following are the basic types:

Type Accepts Example Declaration
number Integers, floats, and fractions let a: number = 10;
string Text values only let s: string = “hello”;
boolean true or false only let b: boolean = true;
any Any value, no checking applied let x: any = 123;
void Absence of a return value function f(): void {}

Number

Takes only integers, floats, fractions, and similar numeric values.

Syntax:

let a :number = 10;
let marks :number = 150;
let price :number = 10.2;

Here are some important methods which can be used on number types:

toFixed() – it will convert the number to a string and keep the decimal places given to the method.

toString() – this method will convert the number to a string.

valueOf() – this method will give back the primitive value of the number.

toPrecision() – this method will format the number to a specified length.

Example : with all number methods

let _num :number = 10.345;
_num.toFixed(2);      // "10.35"
_num.valueOf();      // 10.345
_num.toString();     // "10.345"
_num.toPrecision(2); // "10"

String

String: only string values.

Syntax:

let str :string = "hello world";

Here are some important methods which can be used on string types:

  • split() – this method will split the string into an array.
  • charAt() – this method will give the character at the index given.
  • indexOf() – this method will give the position of the first occurrence of the value given to it.
  • replace() – this method takes 2 strings. It searches for the first value in the string and, if present, replaces it with the second one, giving a new string back.
  • trim() – this method will remove white space from both sides of the string.
  • substr() – this method will give a part of the string, depending on the start position and the length given.
  • substring() – this method will give a part of the string, depending on the start and end positions. The character at the end position is excluded.
  • toUpperCase() – will convert the string to uppercase.
  • toLowerCase() – will convert the string to lowercase.

Example:

let _str:string = "Typescript";

_str.charAt(1);                // y
_str.split("");                // ["T","y","p","e","s","c","r","i","p","t"]
_str.indexOf("s");             // 4, gives -1 if the value does not exist
_str.replace("Type", "Coffee"); // "Coffeescript"
_str.trim();                    // "Typescript"
_str.substr(4, _str.length);   // "script"
_str.substring(4, 10);         // "script"
_str.toUpperCase();             // "TYPESCRIPT"
_str.toLowerCase();             // "typescript"

Boolean

A boolean accepts only the logical values true and false. Unlike plain JavaScript, the numbers 0 and 1 are not accepted, because they are of type number.

Syntax:

let status :boolean = true;
let isDone :boolean = false;

let bflag :boolean = 1;
// error: Type 'number' is not assignable to type 'boolean'

Any

Syntax:

let a :any = 123
a = "hello world"; // changing type will not give any error.

Variables declared using the any type can hold a string, number, array, boolean, or void. TypeScript will not throw any compile-time error, which is similar to variables in JavaScript. Make use of the any type only when you are unsure about the type of value which will be associated with that variable, because it switches off every check on that value.

Void

Void type is mostly used as the return type of a function which does not return anything.

Syntax:

function testfunc():void{
 //code here
}

TypeScript Array

An Array in TypeScript is a data type in which you can store multiple values. Let us learn how to declare and assign values for array operations in TypeScript.

Since TypeScript is a strongly typed language, you have to state the data type of the values in an array. Otherwise, it will be treated as of type any.

Declare and Initialize an Array

Syntax:

let nameofthearray : Array<typehere>

Example

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"]; // array with all string values

let years: Array<number> = [2015, 2016, 2017, 2018, 2019]; // array with all numbers

let month_year: Array<string | number> = ["Jan", 2015, "Feb", 2016]; // mixed

let alltypes: Array<any> = [true, false, "Harry", 2000, { "a": "50", "b": "20" }]; // any type

Different Ways to access elements from an Array

To get the elements from an array, the values start from index 0 up to the length of the array minus one.

let years: Array<number> = [2016, 2017, 2018, 2019];
years[0]; // output will be 2016
years[1]; // output will be 2017
years[2]; // output will be 2018
years[3]; // output will be 2019

You can also get the elements from an array using a TypeScript for loop, as shown below.

Using TypeScript for loop

let years: Array<number> = [2016, 2017, 2018, 2019];
for (let i = 0; i < years.length; i++) {
     console.log(years[i]);
}

Output:

2016
2017
2018
2019

โš ๏ธ Warning: The loop condition must be i < years.length. Writing i <= years.length runs one extra iteration and prints undefined, because the last valid index is always length minus one.

Using for-in loop

let years: Array<number> = [2016, 2017, 2018, 2019];
for (let i in years) {
     console.log(years[i]);
}

Output:

2016
2017
2018
2019

Using for-of loop

let years: Array<number> = [2016, 2017, 2018, 2019];
for (let i of years) {
     console.log(i);
}

Output:

2016
2017
2018
2019

Using forEach loop

let years: Array<number> = [2016, 2017, 2018, 2019];
years.forEach(function(yrs, i) {
  console.log(yrs);
});

Output:

2016
2017
2018
2019

TypeScript Array Methods

The TypeScript Array object has many properties and methods which help developers handle arrays easily and efficiently. You can get the value of a property by specifying arrayname.property, and the output of a method by specifying arrayname.method().

Member Purpose Returns
length Number of elements in the array number
reverse() Reverses the order of items in place The same array
sort() Sorts the items in place The same array
pop() Removes the last item The removed item
shift() Removes the first item The removed item
push() Adds a value as the last item The new length
concat() Joins two arrays into one A new array

Example for length property

let months: Array<string> = ["Jan", "Feb", "March", "April", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec"];

console.log(months.length);  // 12

Example for reverse method

console.log(months.reverse());
// ["Dec","Nov","Oct","Sept","Aug","July","June","May","April","March","Feb","Jan"]

Example for sort method

console.log(months.sort());
// ["April","Aug","Dec","Feb","Jan","July","June","March","May","Nov","Oct","Sept"]

Example for pop method

console.log(months.pop()); // Dec

Example for shift method

console.log(months.shift()); // Jan

Example for push method

let years: Array<number> = [2015, 2016, 2017, 2018, 2019];
console.log(years.push(2020)); // 6, the new length
years.forEach(function(yrs, i) {
  console.log(yrs); // 2015, 2016, 2017, 2018, 2019, 2020
});

Example for concat method

let array1: Array<number> = [10, 20, 30];
let array2: Array<number> = [100, 200, 300];
console.log(array1.concat(array2)); // [10, 20, 30, 100, 200, 300]

Class in TypeScript

TypeScript is a superset of JavaScript, so whatever is possible in JavaScript is also possible in TypeScript. Class is a feature added from ES6 onward. Earlier in JavaScript, class-like functionality was achieved using a function with prototype methods to reuse code. Using class, your code can come close to languages such as Java, C#, and Python, where code is easily reused.

Defining a Class in TypeScript

Here is the basic class syntax in TypeScript:

class nameofclass {
     //define your properties here

    constructor() {
     // initialize your properties here
    }

   //define methods for class
}

Example: A working example on Class

class Students {
    age : number;
    name : string;
    roll_no : number;

    constructor(age: number, name:string, roll_no: number) {
        this.age = age;
        this.name = name;
        this.roll_no = roll_no;
    }

    getRollNo(): number {
        return this.roll_no;
    }

    getName() : string {
        return this.name;
    }

    getAge() : number {
        return this.age;
    }
}

In the above example, you have a class called Students. It has the properties age, name, and roll_no.

Constructor in a TypeScript Class

The class Students defined above has a constructor as shown below:

constructor(age: number, name:string, roll_no: number) {
        this.age = age;
        this.name = name;
        this.roll_no = roll_no;
    }

The constructor method has the parameters age, name, and roll_no. The constructor takes care of initialising the properties when the class is instantiated. The properties are accessed using the this keyword, for example this.age to access age and this.roll_no to access roll_no. You can also have a default constructor, as shown below:

constructor () {}

Methods inside a TypeScript Class

In the class Students there are methods defined, for example getRollNo(), getName(), and getAge(), which return the values of the properties roll_no, name, and age.

getRollNo(): number {
        return this.roll_no;
}

getName() : string {
	return this.name;
}

getAge() : number {
	return this.age;
}

Creating an Instance of a Class in TypeScript

In TypeScript, to create an instance of a class you use the new operator. When you create an instance with new, you get an object which can access the properties and methods of the class, as shown below:

let student_details = new Students(15, "Harry John", 33);
student_details.getAge();  // 15
student_details.getName(); // Harry John

Compiling a TypeScript Class to JavaScript

You can use the tsc command as shown below to compile to JavaScript.

Command: tsc  Students.ts

The output of the JavaScript code on compilation is as shown below:

var Students = /** @class */ (function () {
    function Students(age, name, roll_no) {
        this.age = age;
        this.name = name;
        this.roll_no = roll_no;
    }
    Students.prototype.getRollNo = function () {
        return this.roll_no;
    };
    Students.prototype.getName = function () {
        return this.name;
    };
    Students.prototype.getAge = function () {
        return this.age;
    };
    return Students;
}());

In JavaScript, the class is converted into a self invoked function.

Class Inheritance

Classes can be inherited using the extends keyword in TypeScript.

Class Inheritance Syntax:

class A {
     //define your properties here

    constructor() {
     // initialize your properties here
    }

   //define methods for class

}

class B extends A {
 //define your properties here

    constructor() {
     // initialize your properties here
    }

   //define methods for class

}

class B will be able to share class A methods and properties.

Here is a working example of a class using inheritance:

class Person {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    getName(): string {
        return this.name;
    }

    getAge(): number {
        return this.age;
    }
}

class Student extends Person {
    tmarks: number;
    getMarks(): number {
        return this.tmarks;
    }

    setMarks(tmarks) {
        this.tmarks = tmarks;
    }
}

let _std1 = new Student('Sheena', 24);
_std1.getAge();      // output is 24
_std1.setMarks(500);
_std1.getMarks();    // output is 500

You have two classes, Person and Student. Student extends Person, and the object created from Student can access its own methods and properties as well as those of the class it extends.

Now let us add some changes to the class above.

Example:

class Person {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    getName(): string {
        return this.name;
    }

    getAge(): number {
        return this.age;
    }
}

class Student extends Person {
    tmarks: number;
    constructor(name: string, age: number, tmarks: number) {
        super(name, age);
        this.tmarks = tmarks; // the derived property must be assigned too
    }
    getMarks(): number {
        return this.tmarks;
    }

    setMarks(tmarks) {
        this.tmarks = tmarks;
    }
}

let _std1 = new Student('Sheena', 24, 500);
_std1.getAge();   // output is 24
_std1.getMarks(); // output is 500

The change compared with the previous example is a constructor defined in class Student. The constructor takes the same parameters as the base class, plus any additional parameters of its own.

In TypeScript you need to call super with all the base class parameters. This must be the first statement inside the constructor, because super executes the constructor of the extended class. Any property declared by the derived class, such as tmarks, must then be assigned explicitly, otherwise getMarks would return undefined.

Access Modifiers in TypeScript

TypeScript supports the public, private, and protected access modifiers on your methods and properties. By default, if no access modifier is given, the method or property is considered public and is easily accessible from the object of the class.

In the case of private access modifiers, members are not available from the object of the class and are meant to be used inside the class only. They are not available to an inherited class.

In the case of protected access modifiers, members are meant to be used inside the class and the inherited class, and are not accessible from the object of the class.

Example:

class Person {
    protected name: string;
    protected age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    private getName(): string {
        return this.name;
    }

    getDetails(): string {
        return "Name is " + this.getName();
    }
}

class Student extends Person {
    tmarks: number;
    constructor(name: string, age: number, tmarks: number) {
        super(name, age);
        this.tmarks = tmarks;
    }
    getMarks(): number {
        return this.tmarks;
    }

    getFullName(): string {
        return this.name;
    }

    setMarks(tmarks) {
        this.tmarks = tmarks;
    }
}

let _std1 = new Student('Sheena', 24, 500);
_std1.getMarks();    // output is 500
_std1.getFullName(); // output is Sheena
_std1.getDetails();  // output is Name is Sheena
Modifier Same Class Derived Class Object of the Class
public Yes Yes Yes
protected Yes Yes No
private Yes No No

Interface in TypeScript

One of the core features of TypeScript is interfaces. An interface is a set of rules which needs to be implemented by the entity using it. The entity can be a class, function, or variable. An interface can be made up of properties and methods. You can mark a property or method as optional using the “?” syntax. The interface adds a strong type check for any function, variable, or class implementing it.

Syntax of an Interface in TypeScript

interface Dimension {
    width: string;
    height: string;
}

You have defined an interface named Dimension which has the properties width and height, both of type string.

Now this interface can be implemented by a variable, a function, or a class. Here is an example of a variable implementing the interface Dimension.

Example:

interface Dimension {
    width: string;
    height: string;
}

let _imagedim: Dimension = {
    width: "100px",
    height: "200px"
};

The signature of the interface Dimension has width and height, and both are mandatory. If any property is missed, or a type is changed, it will give a compile-time error while compiling the code to JavaScript.

The above code, when compiled to JavaScript, looks as follows:

var _imagedim = {
    width: "100px",
    height: "200px"
};

Let us now see how to use an interface with a function.

Using an Interface on a function as a return type

interface Dimension {
    width: string;
    height: string;
}

function getDimension() : Dimension {
    let width = "300px";
    let height = "250px";
    return {
        width: width,
        height: height
    }
}

In the above example, the interface Dimension is used as the return type of the function getDimension(). The return value has to match the properties and types declared in the interface.

The compiled JavaScript code will be as follows:

function getDimension() {
    var width = "300px";
    var height = "250px";
    return {
        width: width,
        height: height
    };
}

During compilation, if the return type does not match the interface, it will throw an error.

Interface as a function parameter

interface Dimension {
    width: string;
    height: string;
}

function getDimension(dim: Dimension) : string {
    let finaldim  = dim.width + "-" + dim.height;
    return finaldim;
}

getDimension({width:"300px", height:"250px"}); // "300px-250px"

In the example above, you have used the interface Dimension as a parameter to the function getDimension(). When you call the function, the parameter passed to it must match the rules defined by the interface.

The compiled JavaScript code will be as follows:

function getDimension(dim) {
    var finaldim = dim.width + "-" + dim.height;
    return finaldim;
}
getDimension({ width: "300px", height: "250px" });

Class implementing an Interface

To make use of an interface with a class, you need to use the keyword implements.

Syntax for a class implementing an interface:

class NameofClass implements InterfaceName {
}

The following example shows an interface working with a class.

interface Dimension {
    width : string,
    height: string,
    getWidth(): string;
}

class Shapes implements Dimension {
    width: string;
    height: string;
    constructor (width:string, height:string) {
        this.width = width;
        this.height = height;
    }
    getWidth() {
        return this.width;
    }
}

In the above example, you have defined the interface Dimension with the properties width and height, both of type string, and a method called getWidth() which returns a string.

The compiled JavaScript code will be as follows:

var Shapes = /** @class */ (function () {
    function Shapes(width, height) {
        this.width = width;
        this.height = height;
    }
    Shapes.prototype.getWidth = function () {
        return this.width;
    };
    return Shapes;
}());

Functions in TypeScript

Functions are sets of instructions performed to carry out a task. In JavaScript, most of the code is written in the form of functions and they play a major role. In TypeScript you have classes, interfaces, modules, and namespaces available, but functions still play an important role. The difference between a function in JavaScript and TypeScript is the parameter and return types available with a TypeScript function.

JavaScript function:

function add (a1, b1) {
   return a1+b1;
}

TypeScript function:

function  add(a1 : number, b1: number) : number {
    return a1 + b1;
}

In the function above, the name of the function is add, the parameters are a1 and b1, both of type number, and the return type is also a number. If you pass a string to the function, it will throw a compile-time error while compiling to JavaScript.

Making a call to the function: add

let x = add(5, 10);   // will return 15
let b = add(5);       // error TS2554: Expected 2 arguments, but got 1
let c = add(3,4,5);   // error TS2554: Expected 2 arguments, but got 3
let t = add("Harry", "John");
// error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'

The parameters a1 and b1 are mandatory and will cause an error if not supplied. The parameter types and the return type are equally important and cannot change once defined.

Optional parameters to a function

In JavaScript, all parameters to functions are optional and are considered undefined if not passed. The same is not true in TypeScript. Once you define the parameters you must supply them. If you want a parameter to be optional, add a question mark after the parameter name, as shown below:

function getName(firstname: string, lastname?: string): string {
    return firstname + lastname;
}

let a = getName("John");              // returns Johnundefined
let b = getName("John", "Harry");     // returns JohnHarry
let c = getName("John", "H", "Harry"); // error TS2554: Expected 1-2 arguments, but got 3

Please note that optional parameters must be defined last. You cannot have the first parameter optional and the second mandatory, because the compiler would not know which value was supplied.

Assign Default Values to Params

You can assign default values to parameters as shown below:

function getName(firstname: string, lastname = "Harry"): string {
    return firstname + lastname;
}

let a = getName("John");      // will return JohnHarry
let b = getName("John", "H"); // will return JohnH

Similar to optional parameters, default initialised parameters must also be kept at the end of the parameter list.

Rest Parameters

You have seen how TypeScript handles mandatory parameters, optional parameters, and default value parameters. Now we will look at rest parameters. Rest parameters are a group of optional parameters defined together, using three dots (โ€ฆ) followed by the name of the parameter, which is an array.

Syntax for Rest params:

function testFunc(a: string, ...arr: string[]) :string {
    return a + arr.join("");
}

As shown above, the rest parameter is an array prefixed by three dots. The array will hold all the remaining arguments passed to the function.

Example:

let a = testFunc("Monday", "Tuesday", "Wednesday", "Thursday");
// output is MondayTuesdayWednesdayThursday

Arrow Functions

An arrow function is one of the important features released in ES6, and it is available in TypeScript too. The syntax has a fat arrow in it, which is where the name comes from.

Arrow function Syntax:

var nameoffunction = (params) => {
 // code here
}

What is the use of an Arrow Function?

Let us look at an example to understand the use case of an arrow function.

Example:

var ScoreCard = function () {
    this.score = 0;

    this.getScore = function () {
        setTimeout(function () {
            console.log(this.score);    // gives undefined
        }, 1000);
    }
}

var a = new ScoreCard();
a.getScore();

You have created a function with a property score initialised to 0, and a method getScore which internally uses setTimeout and, after one second, logs this.score. The logged value is undefined even though this.score is defined and initialised. The problem lies with the this keyword. The function inside setTimeout has its own this, and since score is not defined on it, the result is undefined.

The same can be handled using an arrow function, as shown below:

var ScoreCard = function () {
    this.score = 0;

    this.getScore = function () {
        setTimeout(() => {
            console.log(this.score);   // you get 0
        }, 1000);
    }
}

var a = new ScoreCard();
a.getScore();

An arrow function does not have its own this, and instead shares the one from its parent scope, so variables declared outside are accessible with this inside an arrow function. They are useful because of the shorter syntax as well as for callbacks, event handlers, and timing functions.

TypeScript Enums

A TypeScript enum is an object which holds a collection of related values stored together. JavaScript does not support enums natively. Most programming languages such as Java, C, and C++ support enums, and TypeScript makes them available too. Enums are defined using the enum keyword.

How to declare an Enum?

Syntax:

enum NameofEnum {
   value1,
   value2,
    ..
}

Example: Enum

enum Directions {
    North,
    South,
    East,
    West
}

In the above example, you have defined an enum called Directions with the values North, South, East, and West. The values are numbered from 0 for the first entry and increase by 1 for each subsequent entry.

Declare an Enum with a numeric value

By default, if an enum member is not given a value, it takes a number starting from 0. The following example shows an enum with explicit numeric values.

enum Directions {
North = 0,
South = 1,
East = 2,
West = 3
}

You may also assign a starting value, and the following members receive incremented values. For example:

enum Directions {
North = 5,
South, // will be 6
East,  // 7
West   // 8
}

Now North starts at 5, so South is 6, East is 7, and West is 8.

You may also assign values of your choice instead of the defaults. For example:

enum Directions {
North = 5,
South = 4,
East = 6,
West = 8
}

How to access an Enum?

The following example shows how to make use of an enum in your code:

enum Directions {
    North,
    South,
    East,
    West
}

console.log(Directions.North);      // output is 0
console.log(Directions["North"]); // output is 0
console.log(Directions[0]);       // output is North

The compiled JavaScript is as follows:

var Directions;
(function (Directions) {
    Directions[Directions["North"] = 0] = "North";
    Directions[Directions["South"] = 1] = "South";
    Directions[Directions["East"] = 2] = "East";
    Directions[Directions["West"] = 3] = "West";
})(Directions || (Directions = {}));
console.log(Directions.North);
console.log(Directions["North"]);
console.log(Directions[0]);

Since JavaScript does not support enums, the compiler converts the enum into a self invoked function, as shown above. The double assignment is what creates the reverse mapping from number back to name.

Declare an Enum with a string value

You can assign string values of your choice, as shown in the example below.

Example:

enum Directions {
    North = "N",
    South = "S",
    East = "E",
    West = "W"
}

console.log(Directions.North);      // output is N
console.log(Directions["North"]); // output is N
console.log(Directions[0]);       // output is undefined

The compiled JavaScript is as follows:

var Directions;
(function (Directions) {
    Directions["North"] = "N";
    Directions["South"] = "S";
    Directions["East"] = "E";
    Directions["West"] = "W";
})(Directions || (Directions = {}));
console.log(Directions.North);
console.log(Directions["North"]);
console.log(Directions[0]);

โš ๏ธ Warning: String enums have no reverse mapping. Compare the two compiled outputs above: the numeric enum stores both directions, while the string enum stores only name to value. That is why Directions[0] returns undefined for a string enum.

What are the Modules in TypeScript?

Files created in TypeScript have global access, which means variables declared in one file can be accessed in another file. This global nature can cause code conflicts and runtime problems. Export and import module functionality can be used to avoid global variable and function conflicts. This feature arrived in JavaScript with the ES6 release and is also supported in TypeScript.

Why do you need Modules in TypeScript?

The following example shows the issue without modules.

Example test1.ts

let age : number = 25;

You have defined a variable age of type number in test1.ts.

Example test2.ts

In test2.ts you are able to access the variable age defined in test1.ts and also modify it, as shown below:

age = 30; // changed from 25 to 30.
let _new_age = age;

This can create a lot of problems, as the variables are globally available and can be modified from anywhere.

With modules, the code written remains local to the file and cannot be accessed outside it. To share anything from a file, it has to be exported using the export keyword. Export is used when you want a variable, class, function, or interface to be used in another file. Import is used when you want to access an exported item. Doing this keeps the code intact within the file, and even if you define the same variable names, they are not mixed up.

Using Export and Import

There are many ways to export and import. We will discuss the syntax which is most commonly used.

The syntax for import and export 1:

export  nameofthevariable or class name or interface name etc

//To import the above variable or class name or interface you have to use import as shown below:

import {nameofthevariable or class name or interfacename} from "file path here without .ts"

Here is a working example using export and import.

test1.ts

export let age: number = 25;

The export keyword is used to share the age variable with another file.

test2.ts

import { age } from "./test1"
let new_age :number = age;

The import keyword is used to access the age variable, and you need to specify the file location as shown above.

Syntax for import and export 2:

There is another way to export and import, and the syntax is as shown below:

export = classname;

import classname = require("file path of modulename")

When you are using export = to export your module, the import has to use require(“file path of modulename”).

Here is a working example showing that case.

Customer.ts

class Customer {
    name: string;
    age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }

    getName(): string {
        return this.name;
    }
}

export = Customer;

testCustomer.ts

import Customer = require("./Customer");

let a = new Customer("Harry", 30);
alert(a.getName());

Module Loader

Modules cannot work on their own, so you need a module loader to locate the import dependencies, as seen in the TypeScript examples above. The module loaders available are CommonJS for Nodejs and Require.js to run in the browser.

To compile code using the CommonJS module format use the following command:

tsc --module commonjs testCustomer.ts

To compile code using the Requirejs module format use the following command:

tsc --module amd testCustomer.ts

The dependent files will be converted to js files with the command above.

Example testCustomer.ts to testCustomer.js using Requirejs

define(["require", "exports", "./Customer"], function (require, exports, Customer) {
    "use strict";
    exports.__esModule = true;
    var a = new Customer("Harry", 30);
    alert(a.getName());
});

Example Customer.ts to Customer.js using Requirejs

define(["require", "exports"], function (require, exports) {
    "use strict";
    var Customer = /** @class */ (function () {
        function Customer(name, age) {
            this.name = name;
            this.age = age;
        }
        Customer.prototype.getName = function () {
            return this.name;
        };
        return Customer;
    }());
    return Customer;
});

To test it using require.js, you need to create a file called main.js which references the dependencies as shown.

Here is the folder structure:

src/
    Customer.js
    testCustomer.js
    main.js
    require.js  // you can get this file from github or npm install requirejs
    test.html

main.js

define(function (require) {
    var customer = require("./Customer");
    var testCustomer = require("./testCustomer");
});

test.html

<!DOCTYPE html>
<html>
<head>
    <title>TypeScript Module testing using Requirejs</title>
    <script data-main="main" src="require.js"></script>
</head>
<body>
    <h3>Testing modules using Requirejs</h3>
</body>
</html>

Module Loader

Namespaces in TypeScript

A namespace holds a collection of classes, interfaces, variables, and functions together in one file.

Namespace Syntax

namespace name{

export class {
}

export interface {
}

export const constname;

}

The related code is available under one namespace.

Namespace working example: testnamespace.ts

namespace StudentSetup {

    export interface StudDetails {
        name: string;
        age: number;
    }

    export function addSpace(str) { // will add space to the string given
        return str.split("").join(" ");
    }

    export class Student implements StudDetails {
        name: string;
        age: number;

        constructor(studentdetails: StudDetails) {
            this.name = studentdetails.name;
            this.age = studentdetails.age;
        }

        getName(): string {
            return this.name;
        }
    }
}

The name of the namespace is StudentSetup, and you have added an interface StudDetails, a function addSpace, and a class called Student.

Accessing a Namespace

Following is the code where you use the namespace StudentSetup.

testStudentSetup.ts

let a = new StudentSetup.Student({ name: "Harry", age: 20 });

console.log("The name is :" + StudentSetup.addSpace(a.getName()));

The class, interface, or function available inside a namespace has to be referred to using the namespace name, for example StudentSetup.addSpace to access the function and StudentSetup.Student to access the class.

You can compile both files into one js file as shown below:

tsc --outFile namespace.js testnamespace.ts  testStudentSetup.ts

Check the output in the command prompt using the command below:

node namespace.js

Output:

The name is :H a r r y

Ambient Declarations in TypeScript

TypeScript allows you to use third-party JavaScript files using ambient declarations. The advantage of this feature is that you do not have to rewrite the library, and yet you can use all its features with type checking in TypeScript.

Ambient Syntax

To declare an ambient module:

declare module moduleName {
   //code here
}

The ambient file has to be saved as:

filename.d.ts

To use the file filename.d.ts in your .ts file you need to reference it as:

/// <reference path="filename.d.ts"/>

The ambient type declaration in TypeScript refers to the third party library and re-declares the functions required with their own types. For example, consider the small JavaScript library shown below.

Third Party JavaScript file: testString.js

var StringChecks = {
    isString: function (str) {
        return typeof str === "string";
    },

    convertToUpperCase: function (str) {
        return str.toUpperCase();
    },

    convertToLowerCase: function (str) {
        return str.toLowerCase();
    },

    convertToStringBold: function (str) {
        return str.bold();
    }
};

You have an object called StringChecks which has the functions isString, convertToUpperCase, convertToLowerCase, and convertToStringBold.

Creating an Ambient Module in TypeScript

Now we will create an ambient module which references the JavaScript functions above and adds type checks as required.

Filename : tstring.d.ts

declare module TestString {

    export interface StringsFunc {
        isString(str: string): boolean;
        convertToUpperCase(str: string): string;
        convertToLowerCase(str: string): string;
        convertToStringBold(str: string): string;
    }
}

declare var StringChecks: TestString.StringsFunc;

You define a module named TestString and export the interface StringsFunc. Each signature states what the function accepts and returns:

  • isString(str: string): boolean – takes a string and returns a boolean. Passing a number or any other type produces a compile-time error.
  • convertToUpperCase(str: string): string – takes a string and returns a string.
  • convertToLowerCase(str: string): string – takes a string and returns a string.
  • convertToStringBold(str: string): string – takes a string and returns a string.

Since the JavaScript file exposes the object name StringChecks, we finally refer to the same name in the .d.ts file:

declare var StringChecks: TestString.StringsFunc;

Using an Ambient module in TypeScript

Here is the test.ts file which uses the ambient file tstring.d.ts.

/// <reference path="tstring.d.ts"/>
let str1 = StringChecks.isString("Hello World");
console.log(str1);
let str2 = StringChecks.convertToUpperCase("hello world");
console.log(str2);
let str3 = StringChecks.convertToLowerCase("HELLO");
console.log(str3);
let str4 = StringChecks.convertToStringBold("Hello World");
console.log(str4);

Compile with tsc test.ts to produce test.js:

/// <reference path="tstring.d.ts"/>
var str1 = StringChecks.isString("Hello World");
console.log(str1);
var str2 = StringChecks.convertToUpperCase("hello world");
console.log(str2);
var str3 = StringChecks.convertToLowerCase("HELLO");
console.log(str3);
var str4 = StringChecks.convertToStringBold("Hello World");
console.log(str4);

Now you can use test.js in an HTML file together with the library file testString.js.

<html>
<head>
    <title>Test TypeScript Ambient</title>
    <script src="testString.js"></script>
    <script src="test.js"></script>
</head>
<body>
</body>
</html>

Output:

true
HELLO WORLD
hello
<b>Hello World</b>

๐Ÿ’ก Tip: For popular libraries you rarely need to write a .d.ts file yourself. Install the community maintained types instead, for example npm install --save-dev @types/lodash, and the compiler picks them up automatically.

To continue, compare the two languages directly in TypeScript vs JavaScript, revisit JavaScript array methods for the untyped equivalents used here, and study loops in JavaScript and internal and external JavaScript for the browser fundamentals the compiled output relies on.

FAQs

No. A browser executes JavaScript only, so the .ts file must be compiled first with tsc or a bundler. Type annotations are erased during that step and have no runtime cost.

Yes. Enable allowJs in tsconfig.json and rename files one at a time. Because every JavaScript file is already valid TypeScript, the project keeps compiling throughout the migration.

An interface can be reopened and extended, and it is the usual choice for object shapes. A type alias also covers unions, tuples, and primitives, which interfaces cannot express.

Use modules with export and import. Namespaces predate ES modules and remain useful mainly for declaration files and older script based codebases.

Yes, measurably. The compiler rejects hallucinated properties and wrong argument types immediately, so a generated snippet either type checks or reports exactly where it is wrong.

Editor integrations feed the surrounding types and .d.ts files into the model context. Richer annotations therefore produce more accurate completions than loosely typed code does.

Summarize this post with: