Skip to content
SDETRole
SDETRole

TypeScript interview question

What is the difference between an interface and a type alias in TypeScript?

beginner 0–2 yrs #interfaces#type-aliases#declaration-merging#unions

Short answer

Both describe object shapes and are mostly interchangeable. Interfaces can be reopened through declaration merging and extended with extends; type aliases can name any type, including unions, tuples, primitives, mapped and conditional types. Many teams use interfaces for object contracts and types for everything else.

Answer

For describing the shape of an object, interface and type are nearly interchangeable, and you can implement either with a class. The differences are at the edges: type aliases can name any type (unions, tuples, primitives, function types, mapped and conditional types), while interfaces only describe object shapes but support declaration merging and give slightly clearer error messages and extends semantics.

Same result, two syntaxes

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

type UserT = {
  id: number;
  email: string;
};

const a: User = { id: 1, email: 'a@example.com' };
const b: UserT = a; // structurally identical, so assignable

TypeScript is structurally typed, so the name does not matter; the shape does.

Things only type aliases can do

type Browser = 'chromium' | 'firefox' | 'webkit';      // union of literals
type Viewport = [width: number, height: number];        // tuple
type Id = string | number;                              // union of primitives
type Handler = (req: Request) => Promise<Response>;     // function type (interfaces can, but less readable)
type ReadonlyDeep<T> = { readonly [K in keyof T]: ReadonlyDeep<T[K]> }; // mapped
type ElementOf<T> = T extends (infer U)[] ? U : never;  // conditional

Unions are the big one. Modelling an API response as a discriminated union is a type-alias job:

type ApiResult<T> =
  | { ok: true; data: T }
  | { ok: false; error: { code: string; message: string } };

Things only interfaces can do: declaration merging

Declaring the same interface twice merges the members. This is how libraries let you augment their types:

// Augment a global type
declare global {
  interface Window {
    __APP_STATE__: { userId?: string };
  }
}

The same mechanism is used to add custom properties to framework types. With type, a second declaration of the same name is an error.

Extending

interface Admin extends User { permissions: string[] }
type AdminT = UserT & { permissions: string[] };

extends reports a clear error when a property conflicts. An intersection with conflicting property types silently produces never for that property, which can be confusing. TypeScript’s own performance guidance also recommends interfaces over intersections, because the compiler can cache and check them faster in large codebases.

A practical convention

  • interface for object contracts that might be extended or implemented: page object interfaces, fixture types, public API shapes.
  • type for unions, tuples, function signatures and anything derived with utility or mapped types.
  • Enforce consistency with the @typescript-eslint/consistent-type-definitions rule so the debate happens once.

What interviewers look for

  • Recognition that they mostly overlap for object shapes.
  • Specific capabilities: unions and mapped types for type, merging for interface.
  • A concrete use of declaration merging (globals or module augmentation).
  • A pragmatic convention rather than dogma.

A strong answer covers

  • Both can describe object shapes and are often interchangeable
  • Type aliases can represent unions, tuples, primitives, mapped and conditional types
  • Interfaces support declaration merging
  • Extension: extends for interfaces, intersections (&) for types
  • States a sensible team convention
Practise answering under time pressure

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →