Start learning free

LESSON 190 OF 348 · OBJECT-ORIENTED PROGRAMMING

Interfaces in TypeScript: Contracts with interface and implements

Lesson Read the full explanation

TL ; DR:

An interface is a pure contract — a list of methods that a class promises to implement, with no shared data and no shared code. Unlike inheritance ("is a"), interfaces express "can do".


// JS has no `interface` keyword; convention is a stub base class:
class Speaker {
    speak() { throw new Error("Not implemented"); }
}
class Dog extends Speaker {
    speak() { console.log("Woof"); }
}


Full lesson:

An interface defines what a class can do, not how it does it or what it is. A Truck, a Robot, and a Drone aren't the same kind of thing — but they can all Move(). You'd put Move() in a Movable interface and have each one implement it.

Interface vs abstract class

Abstract classInterface
Has fieldsYesUsually no
Has method bodiesYes (some)No (or default impls only)
Multiple "inheritance"Usually noYes — a class can implement many interfaces
Models"is a""can do"

A class inherits from at most one parent class but can implement many interfaces. That's why interfaces are the right tool for cross-cutting capabilities like Comparable, Serializable, Iterable, etc.

The language landscape

  • C# / Java — first-class interface keyword. C# uses : for both inheritance and implementation; Java uses extends for inheritance and implements for interfaces.
  • Python — no separate interface; abstract base classes (ABCs) with all-abstract methods serve the same role.
  • JavaScript — no interface keyword in plain JS (TypeScript has it). The convention is a stub class.
  • C++ — a class with only pure-virtual methods is an interface. Multiple inheritance lets a class implement several.

Interfaces in TypeScript:

Unlike plain JavaScript, TypeScript has a real interface keyword. An interface describes the shape an object or class must have — the methods and properties it must provide — and a class then implements it.

interface Speaker {
    speak(): void;
}

class Dog implements Speaker {
    speak(): void { console.log("Woof"); }
}

The implements keyword makes the compiler check that Dog really provides every member Speaker requires — which is exactly what you'll do in the task below.


Your task

The Speaker interface (or interface-like base) is already declared. Create a Dog class that implements it, with a speak() method that prints "Woof".

Expected output:

Woof
STEP 1 OF 2
    Ctrl + Enter to check

    TYPESCRIPT · OBJECT-ORIENTED PROGRAMMING

    Interfaces in TypeScript, explained

    What an interface is

    An interface describes the shape something must have: which methods and properties it provides, and with which types. It contains no code and no data of its own. Where inheritance says what a class is, an interface says what it can do. A truck, a robot and a drone are different kinds of things, but all three can move, so each can promise the same move() method.

    Unlike plain JavaScript, TypeScript has a real interface keyword:

    interface Speaker {
        speak(): void;
    }

    A class then declares that it keeps the promise with implements:

    class Dog implements Speaker {
        speak(): void {
            console.log("Woof");
        }
    }

    The compiler now checks Dog against Speaker. If a required member is missing or has the wrong type, you get an error on the class declaration.

    The lesson's exercise

    The starter code declares the Speaker interface and, at the bottom, creates a Dog named rex and calls rex.speak(). You write the Dog class in between, and the program must print Woof.

    1. Declare Dog with implements Speaker. Unlike extends, this inherits nothing. It tells the compiler to verify that Dog provides everything the interface lists.
    2. Write speak(): void in the class body. The signature matches the interface: the same name, no parameters, no return value. The body logs Woof with console.log.

    The finished program:

    interface Speaker {
        speak(): void;
    }
    
    class Dog implements Speaker {
        speak(): void {
            console.log("Woof");
        }
    }
    
    const rex = new Dog();
    rex.speak();

    It prints:

    Woof

    Interface or abstract class

    Abstract classInterface
    Method bodiesSome methods can have oneNone, only signatures
    Fields with valuesYesNo, only the type of a property
    How many a class can useExtends one classImplements as many as needed
    Exists at run timeYes, it is a JavaScript classNo, it is erased
    Models"is a""can do"

    A class can extend only one parent, but it can implement several interfaces, separated by commas:

    interface Speaker {
        speak(): void;
    }
    
    interface Mover {
        move(): void;
    }
    
    class Robot implements Speaker, Mover {
        speak(): void { console.log("Beep"); }
        move(): void { console.log("Rolling"); }
    }

    This is why interfaces suit capabilities that cut across unrelated classes: the Robot doesn't have to share a parent with anything else that can speak.

    Interfaces describe shapes, not only classes

    In TypeScript an interface is also a type, and a value fits it when its shape matches. That means a function can accept anything that has the right members, whether or not it was declared with implements:

    interface Speaker {
        speak(): void;
    }
    
    function talk(s: Speaker): void {
        s.speak();
    }
    
    class Cat {
        speak(): void { console.log("Meow"); }
    }
    
    talk(new Cat());
    talk({ speak() { console.log("Plain object"); } });

    This prints:

    Meow
    Plain object

    Cat never mentions Speaker, yet it is accepted, because it has a speak(): void method. This is called structural typing. The implements clause is therefore not what makes a class usable as a Speaker. Its job is to make the compiler check the class right where you write it, so a mistake shows up on the class and not later at some call site.

    Properties work the same way. An interface can list properties, and a property marked with ? is optional:

    interface Named {
        name: string;
        nickname?: string;
    }

    What happens at run time

    Interfaces are erased when TypeScript is compiled to JavaScript. The generated code for the exercise contains the Dog class and nothing for Speaker. Two consequences follow:

    • You can't use an interface as a value. typeof Speaker or x instanceof Speaker is an error, because Speaker only exists as a type. To test for a capability at run time, check the member itself, for example "speak" in obj.
    • The compiler checks only the code it sees. If a class that is missing speak reaches a variable typed Speaker anyway, the program fails when it calls the method, with s.speak is not a function. The compiler already reported an error when it saw the incomplete class, but it still wrote the JavaScript, so fix such errors instead of running past them.

    Common mistakes

    • Leaving out a member. A class that says implements Speaker but has no speak gets the error Class 'Mute' incorrectly implements interface 'Speaker'.
    • Expecting inherited code. implements copies no method bodies. Every implementing class writes its own, or inherits one from a parent class.
    • Using extends where implements is meant. A class implements an interface and extends a class. (An interface can itself extend other interfaces.)
    • Mismatched signatures. The method in the class must be compatible with the interface: a different name, or a required parameter the interface doesn't have, is an error.
    • Treating the interface as a value. new Speaker() doesn't work, since there is nothing to create. Create an object of a class that implements it.

    Key takeaways

    • An interface lists the members something must have, with no implementation.
    • A class promises to follow one with implements, and the compiler checks the promise.
    • A class can implement many interfaces but extend only one class.
    • Interfaces are structural and erased: they cost nothing at run time, and they offer no run-time checks.
    Keep going with TypeScriptAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free