Getting Started with Typescript Classes

Traducciones al Español
Estamos traduciendo nuestros guías y tutoriales al Español. Es posible que usted esté viendo una traducción generada automáticamente. Estamos trabajando con traductores profesionales para verificar las traducciones de nuestro sitio web. Este proyecto es un trabajo en curso.
Create a Linode account to try this guide with a $ credit.
This credit will be applied to any valid services used during your first  days.

TypeScript support for classes was introduced in ECMAScript 6 (ES6). Classes allow programmers to write their code following object-oriented programming (OOP) principles. Class-driven OOP reduces code repetition due to class inheritance and the usage of objects.

Class Declarations

To declare a class in TypeScript you must use the class keyword, provide a class name, and wrap the body of your class in curly braces. The body of the class includes any fields, class constructors, and functions. The example below displays the skeleton of a Rectangle class declaration in TypeScript:

File: example.ts
1
2
3
class Rectangle {
    //class fields, constructor, and functions
}

Fields

Fields (also called properties) are class members. They are public and writeable by default. The type declaration is optional, but if you omit it, the default class is any. The example below contains four fields, x, y, width, and height. Each field’s is of type number.

File: example.ts
1
2
3
4
5
6
class Rectangle {
  x: number;
  y: number;
  width: number;
  height: number;
}

Initializers

Class fields can be initialized to a specific value in a class declaration. Whenever the class is instantiated, the field is initialized to the specified value. The field’s type is inferred from the value of the initializer, so you can omit the type declaration. The example below initializes each field to 0.

File: example.ts
1
2
3
4
5
6
class Rectangle {
  x = 0;
  y = 0;
  width = 0;
  height = 0;
}

Readonly Fields

If you prefix a field with the readonly modifier, you cannot assign a value to the field outside of the class constructor. The read-only members can only be assigned in an initializer or in a class constructor. The example below displays the Rectangle class with a readonly field named pi.

File: example.ts
1
2
3
4
5
6
7
class Rectangle {
  x = 0;
  y = 0;
  width = 0;
  height = 0;
  readonly pi: number = 3.14159;
}

Constructors

A constructor is a type of function that runs when a class is instantiated and initializes the new instance’s variables. Constructors cannot have type parameters and always return the class instance type. The example Rectangle class contains parameters with default values

File: example.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Rectangle {
    x: number;
    y: number;
    width: number;
    height: number;

   constructor(x = 0, y = 0, width = 100, height = 100) {
       this.x = x;
       this.y = y;
       this.width = width;
       this.height = height;
   }
}

const rect1 = new Rectangle(); //uses default constructor parameter values
const rect2 = new Rectangle(100, 200, 300, 400); //assigns new parameter values

You can also create multiple constructors for a class with the same name and different function signatures (parameter type and return types). This concept is called Overloaded Functions.

Methods

Methods are functions that belong to the class. In the example below, the move method affects the x and y values of a rectangle, but not the width, or height. The members of the class can be accessed by using the this. qualifier; an unqualified name in a method body always refers to something in the enclosing scope.

File: example.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Rectangle {
    x: number;
    y: number;
    width: number;
    height: number;

   constructor(x = 0, y = 0, width = 100, height = 100) {
       this.x = x;
       this.y = y;
       this.width = width;
       this.height = height;
   }

   move(dx: number, dy: number) {
       this.x += dx;
       this.y += dy;
   }
}

const rect1 = new Rectangle();  //uses defaults, so 0, 0, 100, 100
const rect2 = new Rectangle(100, 200, 300, 400);

rect1.move(10, 10);

Derived Classes

You can derive one class from another using the extends keyword. The example below adds a title attribute to a rectangle, which would be useful if we were turning the Rectangle class into a Window class. The call to super() is required before using the this qualifier in the derived class’ constructor. TypeScript lets you know if you forget the super() call.

File: example.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Rectangle {
    x: number;
    y: number;
    width: number;
    height: number;

   constructor(x = 0, y = 0, width = 100, height = 100) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
   }

   move(dx: number, dy: number) {
      this.x += dx;
      this.y += dy;
   }
}

class NamedRect extends Rectangle {
    title: string;

    constructor(title = "default", x = 0, y = 0, width = 100, height = 100) {
        super();
        this.title = title;
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
}

const rect1 = new Rectangle();  //uses defaults, so 0, 0, 100, 100
const rect2 = new Rectangle(100, 200, 300, 400);
const nr = new NamedRect("window", 10, 20, 30, 40);

rect1.move(10, 10);
nr.move(20, 20);

Method Overrides

A derived class can also override a base class field or property. The derived class must be a subtype of its base class. In the example above, the derived class NamedRect could re-implement the move method of its base class.

Getters and Setters

TypeScript supports getters (get keyword) and setters (set keyword) in classes. They are rarely useful unless you need to add logic, such as range checks or type conversions on setters. A getter is also called an Accessor and a setter is also called a Mutator. The below example demonstrates how to access a public property of the Thing class.

File: example2.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Thing {
    _size = 0;

    // Getter method to return size of Thing class
    get size(): number {
        return this._size;
    }

    // Setter method to set the value of size
    set size(value: string | number | boolean) {
        let num = Number(value);

        // Don't allow NaN, Infinity, etc

        if (!Number.isFinite(num)) {
            this._size = 0;
            return;
        }

        // Setter call
        // Access the public property _size of the Thing class
        this._size = num;
    }
}

In the above example, you can notice that the call to the setter method does not have parentheses like a regular method. When you call this._size, the size setter method is invoked and value is assigned.

Interfaces and Implementations

Like C#, TypeScript lacks multiple inheritance but has interfaces, which define characteristics such as structures or method names that must be implemented by classes that use them.

In the example below, the Pingable interface requires a ping() method. The Sonar class implements it correctly; the Ball class does not.

File: example3.ts
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
interface Pingable {
  ping(): void;
}

class Sonar implements Pingable {
  ping() {
    console.log("ping!");
  }
}
class Ball implements Pingable {

  // error here
  pong() {
    console.log("pong!");
  }
}

Here, the Pingable interface is implemented in the Sonar and Ball classes using the implements keyword. The implementing classes should strictly define the properties and the function with the same signatures. If not, the compiler throws an error.

Running the above example3.ts displays the following error:

Class 'Ball' incorrectly implements interface 'Pingable'.
Property 'ping' is missing in type 'Ball' but required in type 'Pingable'.

Member Visibility

You can control the visibility of the TypeScript methods or properties using the TypeScript data or access modifiers. Following are the different access modifiers in TypeScript:

  • public: This is the default visibility. Public members can be accessed from anywhere.
  • protected: Protected members can only be accessed from subclasses of the class where they are declared.
  • private: Private members can only be accessed from the class where they are declared.
  • static: Static members are common to all instances of a class, instead of being unique to each instance. TypeScript doesn’t have or need static classes: simply use a free (non-class) variable or function. The static attribute can be combined with any of the other visibility attributes.
  • Generic Classes (Generics): Like functions and interfaces, classes may use generics, denoted by the type variable <Type> or <T> after the class name. <Type> or <T> is a special kind of variable that denotes types.
File: example4.ts
1
2
3
4
5
6
7
class Box<Type> {
  contents: Type;
  constructor(value: Type) {
    this.contents = value;
  }
}
const b = new Box("hello!");

Using Generics, you can create reusable components that can work with any data type without restricting to one data type. In the above example, the type of const b is Box<string>.

Note
The members of a generic class that use the type can’t be “static”. Generic classes are usually more efficient at runtime than classes that use variables of type any.

Arrow Functions

The arrow function expression => (a shortcut for an anonymous or lambda function) is sometimes used in classes instead of traditional method definitions.

File: example5.ts
1
2
3
4
5
6
class MyClass {
  name = "MyClass";
  getName = () => {
    return this.name;
  };
}

One reason to do so is to make it simpler to use this correctly. You might benefit from reading about this at Runtime in Classes in the TypeScript documentation since the underlying JavaScript behavior is deeply weird.

Abstract Classes and Members

As in C#, you can create abstract base classes in TypeScript that lack one or more method implementations, which are also marked abstract.

File: example6.ts
1
2
3
4
5
6
abstract class Base {
  abstract getName(): string;
  printName() {
    console.log("Hello, " + this.getName());
  }
}

This forces you to create a derived class that implements the abstract members before you can instantiate the class. Using abstract classes well requires some fairly sophisticated design. A good example might be an abstract reader class that has derived classes for the various file types supported (text, csv, and so on); the base class provides a common interface for all the implementations.

Further Information

To learn more, there’s plenty of TypeScript documentation available and the TypeScript Playground gives you the flexibility to write and learn TypeScript.

This page was originally published on


Your Feedback Is Important

Let us know if this guide was helpful to you.


Join the conversation.
Read other comments or post your own below. Comments must be respectful, constructive, and relevant to the topic of the guide. Do not post external links or advertisements. Before posting, consider if your comment would be better addressed by contacting our Support team or asking on our Community Site.
The Disqus commenting system for Linode Docs requires the acceptance of Functional Cookies, which allow us to analyze site usage so we can measure and improve performance. To view and create comments for this article, please update your Cookie Preferences on this website and refresh this web page. Please note: You must have JavaScript enabled in your browser.