Jiaxi Liu (Jesse)

Master’s Graduate

Software Engineer | Scalable APIs · Web Scraping · Data Integration · Code Quality & Refactoring

Back to Blog

TypeScript interface, type, abstract class, and Generics Compared

interface, type, and abstract class can all describe structure, but they are not interchangeable in every situation.

interface

interface is commonly used to describe object shapes, especially public APIs and class contracts.

interface User {
  id: string;
  name: string;
}
 
class Admin implements User {
  constructor(
    public id: string,
    public name: string,
  ) {}
}

Interfaces can be merged through repeated declarations, which can be useful when extending third-party types.

type

type is more flexible for unions, intersections, and complex combinations.

type Status = "idle" | "loading" | "success" | "error";
type UserWithRole = User & { role: string };

Use type for state unions, function types, and composed type logic.

abstract class

An abstract class can define both a type contract and shared implementation.

abstract class Repository<T> {
  abstract findById(id: string): Promise<T | null>;
 
  logQuery(id: string) {
    console.log(`find ${id}`);
  }
}

Use abstract classes when subclasses should share actual code.

Generics

Generics parameterize types.

function identity<T>(value: T): T {
  return value;
}
 
const name = identity<string>("Alice");

They are common in collections, API responses, and utility functions.

interface ApiResponse<T> {
  data: T;
  error?: string;
}
 
type UserResponse = ApiResponse<User>;

Simple Selection Rules

  • Object shape: prefer interface
  • Union, intersection, utility type: prefer type
  • Shared implementation with subclass requirements: use abstract class
  • Reusable type logic: use generics