Page Content

Tutorials

How do you Implement an Interface in a Class in TypeScript?

Interface in a Class in TypeScript

TypeScript’s interface-class relationship is essential to using the language’s static typing features in an object-oriented framework. Because it is structurally typed, TypeScript mostly depends on interfaces to provide the desired “shape” or organisation of variables and objects. The constructs that provide these shapes tangible, executable implementations are called classes.

One important difference is that interfaces only exist inside the TypeScript type system and don’t affect JavaScript at runtime. Interface declarations are lost during the compilation (transpilation) of TypeScript code to JavaScript. Classes, on the other hand, compile to ES6 classes or JavaScript functions that reflect the structure and behaviour of the runtime.

Class Implementation using

With TypeScript, a class can use the implements keyword to explicitly state that its instances follow the structure specified by one or more interfaces. By precisely providing all of the attributes and methods specified in the interface, this keyword acts as a vital compile-time safety check.

Structure and Enforcement

A class that implements an interface needs to contain all of the fields and functions that the interface specifies. A missing member will be indicated and the codebase will stay in sync if the external interface structure changes because the compiler will detect the incompatibility right at the class declaration site.

Only the class instances’ structure is subject to the constraint imposed by implements. Additionally, classes may implement more than one interface, in which case they must meet the shape specifications of each interface that is given.

This process makes polymorphism possible. Classes implementing interfaces ensure that they are compatible types, allowing for flexible dependency injection and substitution, because any object that structurally matches an interface can be considered as that interface’s type (Duck Typing).

Code Example: Implementing an Interface

Here is a demonstration of a class implementing a Movable interface:

TypeScript Code (Implements Interface)

interface Movable {
    position: number;
    move(distance: number): void;
}

class Car implements Movable {
    // 1. Must define all properties required by Movable
    public position: number = 0; 
    
    // Private members are allowed but ignored by the interface
    private speed: number = 42; 

    // Constructor to initialize
    constructor() { 
        // implementation details
    }

    // 2. Must implement all methods required by Movable
    public move(distance: number): void { 
        this.position += distance;
        console.log(`Car moved to position: ${this.position}`);
    }
}

// Example usage
const myCar = new Car();
myCar.move(10);
// myCar now has the structural type Movable

Output/Explanation:

If Movable required position: number but Car omitted it or provided position: string, a compile-time error would occur. The class Car is now guaranteed to have the necessary position field and move method.

Car moved to position: 10

Interfaces Defining Constructors

Although interfaces specify a class’s instance shape, they can also specify the shape of the constructor function. This feature is essential for accurately typing classes that are handled as values instead than just types for their instances. At the type level, classes produce two terms: one for the class constructor (which may be accessed using the typeof operator) and one for the instance.

The construct signature, which is preceded with the new keyword and syntactically resembles a function call signature, is used by interfaces to create constructors.

Structure of a Constructor Interface

The expected arguments for instantiation and the type of returned instance are specified in a construct signature. When defining factory patterns or sending a class as a parameter to a function (dependency injection), this pattern is commonly utilised.

This is how a constructor interface’s type signature appears: : new(parameterList): returnType.

Code Example: Interface for a Constructor

Any conforming class must generate an instance of type NamedItem and accept a string parameter in its constructor, according to IConstructable.

// Define the shape of the instance
interface NamedItem {
    name: string;
}

// Define the shape of the constructor
interface IConstructable {
    new (label: string): NamedItem; 
}

// A function that requires a class/constructor adhering to IConstructable
function createItem(ctor: IConstructable): NamedItem { 
    return new ctor("Generated Name"); 
}

// A class that structurally conforms to NamedItem
class MyNamedItem implements NamedItem {
    name: string;
    constructor(label: string) {
        this.name = `Item: ${label}`;
    }
}

// Usage: MyNamedItem adheres to IConstructable structurally
const item = createItem(MyNamedItem);
console.log(item.name); 

Output/Explanation:

The createItem function requires a constructor that can be called with new and one string argument. MyNamedItem satisfies this requirement.

Item: Generated Name

Structural vs. Nominal Typing

TypeScript uses a structural type system. This indicates that, unlike nominal systems like C# or Java, which rely on explicit declarations or inheritance chains to determine type compatibility, types are based on the members they hold. The saying “if it looks like a duck and quacks like a duck, it’s probably a duck” is frequently used to illustrate the idea.

  1. Implicit Implementation: If an object’s shape satisfies the interface’s requirements, it can be assigned to an interface type even if the class did not explicitly use the implements keyword thanks to structural typing.
  2. Explicit Enforcement: Although implementation is implicit, developers usually use implements to enforce the contract at the declaration stage when defining a class. As a precaution, it instructs the compiler to verify compatibility beforehand rather than waiting for an error when the class instance is subsequently utilised in another context.

In Conclusion

Classes give real runtime implementations, whereas interfaces define abstract, development-time structural contracts. The implements keyword supports a crucial component of TypeScript’s type-safe polymorphism by explicitly connecting a class to an interface for compile-time enforcement.

Index