TypeScript: TypeScript Classes and Interfaces

Last updated: 2026-08-26

Classes and interfaces are the two pillars of object-oriented programming in TypeScript—classes provide implementations, while interfaces define contracts. When a class implements an interface, TypeScript ensures that the class satisfies all the requirements specified by the interface.

1. A class implements an interface (implements)

(1) Basic Syntax

TYPESCRIPT
interface Printable {
  toString(): string;
}

class User implements Printable {
  constructor(public name: string, public age: number) {}

  toString(): string {
    return `${this.name},${this.age} years old`;
  }
}

let user = new User("Charlie", 20);
console.log(user.toString());  // "Charlie,20 years old"

(2) The Significance of Implementing Interfaces

An interface is a "contract"—when a class implements an interface, it promises, "I will provide all the properties and methods required by the interface":

TYPESCRIPT
interface Animal {
  name: string;
  speak(): string;
  move(distance: number): void;
}

class Dog implements Animal {
  constructor(public name: string) {}

  speak(): string {
    return "Woof!";
  }

  move(distance: number): void {
    console.log(`${this.name} Moved ${distance}m`);
  }
}

// ❌ Members that do not meet the interface requirements will result in an error.
// class Cat implements Animal {
//   constructor(public name: string) {}
//   // Missing speak and move → Compilation Error
// }

(3) Multi-interface Implementation

A class can implement multiple interfaces—separated by commas:

TYPESCRIPT
interface Serializable {
  serialize(): string;
}

interface Comparable {
  compareTo(other: this): number;
}

class Score implements Serializable, Comparable {
  constructor(public value: number) {}

  serialize(): string {
    return JSON.stringify({ value: this.value });
  }

  compareTo(other: Score): number {
    return this.value - other.value;
  }
}

let s1 = new Score(90);
let s2 = new Score(85);

console.log(s1.serialize());       // '{"value":90}'
console.log(s1.compareTo(s2));     // 5(Positive Number Display s1 > s2)

▶ Example: Defining a Unified API Using Interfaces

Output:

TEXT 📖 Display only
Charlie
2
TYPESCRIPT
interface Repository<T> {
  findById(id: number): T | null;
  findAll(): T[];
  save(entity: T): void;
  delete(id: number): boolean;
}

interface User {
  id: number;
  name: string;
  email: string;
}

class UserRepository implements Repository<User> {
  private users: User[] = [];

  findById(id: number): User | null {
    return this.users.find(u => u.id === id) ?? null;
  }

  findAll(): User[] {
    return [...this.users];
  }

  save(entity: User): void {
    let index = this.users.findIndex(u => u.id === entity.id);
    if (index >= 0) {
      this.users[index] = entity;  // Update
    } else {
      this.users.push(entity);     // New
    }
  }

  delete(id: number): boolean {
    let len = this.users.length;
    this.users = this.users.filter(u => u.id !== id);
    return this.users.length < len;
  }
}

let repo = new UserRepository();
repo.save({ id: 1, name: "Charlie", email: "xiao@example.com" });
repo.save({ id: 2, name: "Diana", email: "hong@example.com" });

console.log(repo.findById(1)?.name);  // "Charlie"
console.log(repo.findAll().length);   // 2

Output:

TEXT 📖 Display only
Charlie
2


2. Classes That Inherit from Interfaces

A unique feature of TypeScript—interfaces can inherit member definitions from classes (inheriting only the type declarations, not the implementations):

TYPESCRIPT
class Control {
  private state: string = "active";

  protected getState(): string {
    return this.state;
  }
}

// Interface-Inherited Classes——Inherit only the type signature
interface Selectable extends Control {
  select(): void;
}

// When a class implements an interface, it must provide all members.
class Dropdown implements Selectable {
  private state: string = "active";  // You must implement it yourself. private Members

  protected getState(): string {
    return this.state;
  }

  select(): void {
    console.log("Selected:" + this.getState());
  }
}
💡 Purpose: Interface-inheriting classes are primarily used in complex class hierarchies to describe types that "have the structure of a certain class while also possessing additional capabilities." They are not commonly used in everyday development.



3. Abstract Classes (abstract)

An abstract class is a "half-finished class"—it provides a partial implementation, and subclasses must complete the rest:

(1) Basic Syntax

TYPESCRIPT
abstract class Shape {
  // Abstract Methods——Not implemented,Subclasses must implement
  abstract getArea(): number;
  abstract getPerimeter(): number;

  // Specific Methods——Implemented,Direct Inheritance by Subclasses
  describe(): string {
    return `Area:${this.getArea().toFixed(2)},Perimeter:${this.getPerimeter().toFixed(2)}`;
  }
}

class Circle extends Shape {
  constructor(public radius: number) {
    super();
  }

  getArea(): number {
    return Math.PI * this.radius ** 2;
  }

  getPerimeter(): number {
    return 2 * Math.PI * this.radius;
  }
}

class Rectangle extends Shape {
  constructor(public width: number, public height: number) {
    super();
  }

  getArea(): number {
    return this.width * this.height;
  }

  getPerimeter(): number {
    return 2 * (this.width + this.height);
  }
}

// ❌ Abstract classes cannot be instantiated directly.
// let shape = new Shape();

let circle = new Circle(5);
let rect = new Rectangle(4, 6);

console.log(circle.describe());  // "Area:78.54,Perimeter:31.42"
console.log(rect.describe());    // "Area:24.00,Perimeter:20.00"

(2) Abstract Classes vs. Interfaces

Feature Abstract Class Interface
Implementation Method May have a specific implementation Must not have any implementation
Constructor Can have Cannot have
Multiple inheritance Single inheritance only Multiple inheritance allowed (extends)
Access Modifiers Supports public/private/protected Properties are public by default
Instantiation Cannot be instantiated directly Cannot be instantiated (pure type)
Exists at runtime Yes (compiled to a JS class) No (pure type declaration)

(3) When to Use Abstract Classes

(4) When to Use Interfaces

▶ Example: Implementing the Template Method Pattern with an Abstract Class

Output:

TEXT 📖 Display only
HELLO WORLD
[Reversal] dlrow olleh
TYPESCRIPT
abstract class DataParser {
  // Template Method——Define the Algorithm Framework
  parse(input: string): string {
    let raw = this.read(input);
    let validated = this.validate(raw);
    let transformed = this.transform(validated);
    return this.format(transformed);
  }

  // Specific Methods——Shared by all subclasses
  private read(input: string): string {
    return input.trim();
  }

  // Abstract Methods——Each subclass implements it on its own
  protected abstract validate(data: string): string;
  protected abstract transform(data: string): string;

  // Hook Method——Subclasses may choose to override this method
  protected format(data: string): string {
    return data;
  }
}

class UpperParser extends DataParser {
  protected validate(data: string): string {
    if (data.length === 0) throw new Error("Input is empty");
    return data;
  }

  protected transform(data: string): string {
    return data.toUpperCase();
  }
}

class ReverseParser extends DataParser {
  protected validate(data: string): string {
    return data;
  }

  protected transform(data: string): string {
    return data.split("").reverse().join("");
  }

  protected format(data: string): string {
    return `[Reversal] ${data}`;
  }
}

let upper = new UpperParser();
let reverse = new ReverseParser();

console.log(upper.parse("  hello world  "));     // "HELLO WORLD"
console.log(reverse.parse("  hello world  "));    // "[Reversal] dlrow olleh"

Output:

TEXT 📖 Display only
HELLO WORLD
[Reversal] dlrow olleh


4. Using Classes as Types

A class definition is itself a type—you can use the class name as the type of a variable:

(1) The Concept of a Class

TYPESCRIPT
class Point {
  constructor(public x: number, public y: number) {}

  distanceTo(other: Point): number {
    return Math.sqrt((this.x - other.x) ** 2 + (this.y - other.y) ** 2);
  }
}

// Class as a Type——Accept Point Instances or structurally compatible objects
let p1: Point = new Point(1, 2);
let p2: Point = { x: 3, y: 4 };   // ✅ Structural Compatibility(But does not include methods!)

console.log(p1.distanceTo(p2));    // ✅ p1 has distanceTo method
// p2.distanceTo(p1);              // ❌ p2 Only x and y,There is no way
⚠️ Note: The type section of a class contains only instance properties and method signatures. When assigning a struct-compatible object, methods are not included—only properties are matched. To access methods, you should create an instance using new Point().

(2) Class Type vs. the typeof Operator

TYPESCRIPT
class Factory {
  static create(): Factory {
    return new Factory();
  }

  constructor(public name: string) {}
}

// Factory Type——Instance Type
let instance: Factory = new Factory("Products");

// typeof Factory Type——The class itself(Constructor Types)
let FactoryClass: typeof Factory = Factory;
let another = FactoryClass.create();  // ✅ Calling a Static Method

▶ Example: Implementing Multiple Interfaces in a Single Class

TYPESCRIPT
interface Loggable {
  log(): string;
}

interface Serializable {
  serialize(): string;
}

class Task implements Loggable, Serializable {
  constructor(
    public id: number,
    public title: string,
    public done: boolean = false
  ) {}

  log(): string {
    return `Task #${this.id}: ${this.title} [${this.done ? "done" : "pending"}]`;
  }

  serialize(): string {
    return JSON.stringify({ id: this.id, title: this.title, done: this.done });
  }
}

let task = new Task(1, "Learn TypeScript");
console.log(task.log());         // "Task #1: Learn TypeScript [pending]"
console.log(task.serialize());   // '{"id":1,"title":"Learn TypeScript","done":false}'
▶ Try it Yourself

Output:

TEXT 📖 Display only
Task #1: Learn TypeScript [pending]
{"id":1,"title":"Learn TypeScript","done":false}

❓ FAQ

Q What is the difference between implements and extends?
A implements means "implements an interface"—a class promises to provide all the members required by the interface, but does not inherit any implementation code. extends means "inherits from a class"—a subclass inherits all the implementation code from the superclass and can override it. A class can implements multiple interfaces, but can only extends one superclass.
Q Which should I use—an abstract class or an interface?
A A simple rule: if multiple classes need to share implementation code, use an abstract class; if you only need to define a contract specifying "what it can do," use an interface. You can combine the two—an interface defines capabilities, and an abstract class provides partial implementation.
Q Can a class that implements an interface have extra members?
A Yes. A class that implements an interface is only required to have "at least the members specified by the interface"; extra members are perfectly valid. For example, interface Printable { print(): void } and class Document implements Printable { print() {...}; save() {...} }—the Document class has an additional save method, but this is perfectly valid.
Q Can an interface inherit from an abstract class?
A Yes. interface ISelect extends AbstractControl {} This is valid—the interface will inherit all member signatures from the abstract class (including those of private members). However, classes that implement this interface must provide their own implementations for all members, including private ones.

📖 Summary

📝 Exercises

  1. Basic Problem (Difficulty ⭐): Define the Loggable interface (with a log method), and have the User and Product classes implement it, respectively. Create instances and call the log method.
  2. Advanced Problem (Difficulty ⭐⭐): Define an abstract class Vehicle (with a brand property, an abstract start method, and a concrete describe method), then create subclasses Car and Bike that implement the start method, respectively. Write a function that takes a parameter of type Vehicle and calls the describe method.
  3. Challenge (Difficulty: ⭐⭐⭐): Design a SortableCollection<T> interface (with a length property, a compare method, and a swap method), and have the NumberCollection class implement it. Then, implement the bubble sort algorithm in the Sorter abstract class (using the interface methods), so that subclasses only need to provide concrete implementations of compare and swap.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏