RizTech Academy logo
RizTech Academy
Objects, Interfaces and Type AliasesLesson 2 of 525 min

Interfaces

Writing { name: string; age: number; city: string } every time you refer to a member is tedious and repetitive. You give the shape a name once and reuse it — and the classic tool for that is the interface. This lesson is interfaces: declaring them, extending them, and the one thing they do that type aliases (the next lesson) cannot.

Naming a shape

interface Member {
  name: string;
  age: number;
  city: string;
}

const kavita: Member = { name: "Kavita", age: 33, city: "Pune" };

function greet(m: Member): string {
  return `Namaste, ${m.name} from ${m.city}`;
}

interface Member { ... } declares a named shape. Now you write Member wherever you mean "an object with those properties" — in variable types, function parameters, return types, arrays (Member[]). The shape is defined in one place, and if it changes, every use updates. Note there are no commas between members in an interface — semicolons or newlines separate them (commas work too, but semicolons are the convention).

An interface is checked exactly like the inline object type from the last lesson — the same excess-property checking on literals, the same structural compatibility. It is purely a naming convenience: Member and { name: string; age: number; city: string } are interchangeable.

Extending interfaces — building on a shape

Interfaces compose through extension — one interface can build on another, adding properties:

interface Person {
  name: string;
  age: number;
}

interface Employee extends Person {
  employeeId: string;
  department: string;
}

const ravi: Employee = {
  name: "Ravi",
  age: 40,
  employeeId: "E123",
  department: "Engineering",
};

Employee extends Person means "an Employee has everything a Person has, plus employeeId and department". This is how you model "is a specialised kind of" relationships and avoid repeating common properties. An interface can extend several others at once (interface C extends A, B), merging all their properties — useful for combining small, focused shapes.

Methods and function properties

An interface can describe objects that have functions, in two equivalent ways:

interface Repository {
  find(id: number): Member | undefined;      // method shorthand
  save: (member: Member) => void;             // function-property form
}

Both declare a property that is a function; the first is the common "method" style, the second is a property whose type is a function type (the functions module goes deep on function types). Use the method shorthand for what reads as an object's behaviour, and the property form when you want to be explicit that it holds a function value.

The interface superpower: declaration merging

Here is the one thing interfaces do that type aliases cannot, and the main reason to know both exist. You can declare the same interface twice, and TypeScript merges them:

interface Window {
  title: string;
}

interface Window {
  version: number;
}

// TypeScript treats Window as { title: string; version: number }

Declaring interface Window a second time does not conflict — TypeScript combines the declarations. This is declaration merging, and it is deliberate: it lets you augment a type you do not own. The classic use is adding a property to a global or library type — extending the browser's Window, or adding a field to a third-party library's types — which the declaration-files lesson (real-projects module) covers. You will rarely author merging yourself, but you must know it happens, because it explains behaviour that would otherwise be baffling (why re-declaring an interface does not error), and it is the mechanism behind a lot of library extensibility.

A type alias, by contrast, cannot be declared twice — a second type Window = ... is a "Duplicate identifier" error. So: interfaces merge; type aliases do not. That is the practical difference the next lesson weighs.

Interfaces are open; that has a cost too

Declaration merging makes interfaces "open" — anyone can add to them anywhere. That is powerful for library authors and occasionally surprising for everyone else: a property might be added to your interface by code you did not write (a library's type augmentation). This is rarely a problem, but it is the flip side of the superpower — an interface is not a closed, final definition the way a type alias is. For your own application's data shapes, this openness usually does not matter; for a shape you want to be definitively fixed, a type alias's closedness is arguably tidier. The next lesson makes the full comparison.

Check your work

What an interface does. Names an object shape so you can reuse it in one place instead of repeating the inline type.

How members are separated. By semicolons or newlines (no commas needed) — semicolons are the convention.

Is an interface checked differently from an inline object type? No — same excess-property checking on literals, same structural compatibility; it is purely a naming convenience.

What extends does. Builds a new interface on an existing one, adding properties — and can extend several at once.

Two ways to type a function member. The method shorthand find(id): T and the function-property form save: (m) => void.

The interface superpower. Declaration merging — the same interface declared twice is combined.

Why merging matters. It lets you augment types you do not own (globals, libraries) — the mechanism behind much library extensibility.

The key difference from a type alias. Interfaces merge (and are "open"); type aliases cannot be redeclared (and are closed).

Practice

  1. Declare an interface Member and use it as a variable type, a parameter type, and an array type.
  2. Change a property in the interface and confirm every use updates.
  3. Assign a literal with an extra property to a Member variable and confirm excess-property checking still fires.
  4. Write interface Employee extends Person and construct an Employee. Omit a Person property and read the error.
  5. Extend two interfaces at once (interface C extends A, B) and confirm the result has all properties.
  6. Declare a Repository interface with a method and a function property, and implement it.
  7. Declare the same interface twice with different properties and confirm TypeScript merges them (no error). Then try the same with a type alias and read the duplicate-identifier error.

Official documentation

Next: type aliases, and the interface-versus-type decision.

Stuck on this lesson?

Being stuck is part of it — but being stuck alone for three days is not. Our internship programme pairs this curriculum with code review and one-to-one help from working developers, and it is free.

About the internship