Skip to content
Educora
Intermediate16 min4 / 8

Interfaces and type aliases

Describe the shape of objects with `interface` and `type`, use optional and `readonly` properties, extend interfaces and learn when to choose which.

Check yourself
In this lesson you will learn
  • Describe an object's shape with interface and type
  • Use optional (?) and read-only (readonly) properties
  • Extend an interface with extends
  • Explain the difference between interface and type, and structural typing

In a school's online gradebook, a student object travels through dozens of functions: it is added to a list, its marks are calculated, it is shown on the screen. Every time the same question comes up: which properties does this object have? grade or class? Is there always an email? In TypeScript you describe the object's shape once and reuse that description everywhere — and the compiler makes sure it is followed.

Describing an object's shape

Definition
Interface

A named type that describes which properties an object must have and what their types are. It is declared with the keyword interface and produces no JavaScript at all — it exists only for checking.

TypeScript
interface Student {
  readonly id: number;
  name: string;
  grade: number;
  email?: string;
}

const aysel: Student = { id: 1, name: 'Aysel', grade: 9 };
const murad: Student = { id: 2, name: 'Murad', grade: 10, email: 'murad@example.com' };

function describe(s: Student): string {
  const contact = s.email ?? 'no email';
  return `#${s.id} ${s.name}, grade ${s.grade} (${contact})`;
}

console.log(describe(aysel));
console.log(describe(murad));
Expected output
#1 Aysel, grade 9 (no email)
#2 Murad, grade 10 (murad@example.com)
  • email?: string is an optional property: the object may not have it, and when you read it, its type is string | undefined. That is why we gave a fallback with ??.
  • readonly id: number is a read-only property: it is set when the object is created and can't be changed afterwards.
  • Properties are separated by semicolons or commas; their order doesn't matter.

Now let's try to break the contract: forget a property, add an extra one and change a readonly field.

TypeScript
interface Student {
  readonly id: number;
  name: string;
  grade: number;
}

const leyla: Student = { id: 3, name: 'Leyla' };
const elvin: Student = { id: 4, name: 'Elvin', grade: 8, age: 14 };
elvin.id = 5;
Text
students.ts:7:7 - error TS2741: Property 'grade' is missing in type '{ id: number; name: string; }' but required in type 'Student'.

7 const leyla: Student = { id: 3, name: 'Leyla' };
        ~~~~~

  students.ts:4:3
    4   grade: number;
        ~~~~~
    'grade' is declared here.

students.ts:8:58 - error TS2353: Object literal may only specify known properties, and 'age' does not exist in type 'Student'.

8 const elvin: Student = { id: 4, name: 'Elvin', grade: 8, age: 14 };
                                                           ~~~

students.ts:9:7 - error TS2540: Cannot assign to 'id' because it is a read-only property.

9 elvin.id = 5;
        ~~
Three mistakes, three different codes: a missing property (TS2741), an extra property (TS2353) and an assignment to a readonly field (TS2540).

Extending and type aliases

An interface can extend another interface with extends — like inheritance in classes: Teacher gets all of Person's properties and adds its own. A type alias, on the other hand, gives a name to any type with the keyword type: an object, a union, a tuple, even a primitive.

TypeScript
interface Person {
  name: string;
}

interface Teacher extends Person {
  subject: string;
}

type Point = { x: number; y: number };
type ID = number | string;

const teacher: Teacher = { name: 'Elvin', subject: 'Physics' };
const start: Point = { x: 0, y: 0 };
const code: ID = 'A-17';

console.log(`${teacher.name} teaches ${teacher.subject}`);
console.log(start, code);
Expected output
Elvin teaches Physics
{ x: 0, y: 0 } A-17
ID can be either a number or a string — we will study such unions in detail in the next lesson.

interface or type?

Featureinterfacetype
Describe an object's shape✓✓
Extendextends& (intersection)
Name a union, a tuple or a primitive✗✓
Re-declare with the same name to merge✓✗
Two interface declarations with the same name merge automatically (declaration merging); two type declarations with the same name are an error.

Structural typing

TypeScript compares types by their structure, not by their names. If an object has the required properties, it fits the type — no matter how it was created. The extra-property error (TS2353) only appears when an object is written directly as a literal, because there an extra property is most likely a typo.

TypeScript
interface Named {
  name: string;
}

function hello(thing: Named): string {
  return `Hello, ${thing.name}!`;
}

const dog = { name: 'Rex', legs: 4 };
console.log(hello(dog));
console.log(hello({ name: 'Baku' }));
Expected output
Hello, Rex!
Hello, Baku!
dog was never declared as Named and has an extra legs property, but it fits because it has a name.

Key points

  • interface and type describe which properties and types an object has; they produce no JavaScript.
  • prop?: T is an optional property; readonly prop: T can't be changed after creation.
  • An interface is extended with extends; type can name any type, including a union.
  • The compiler catches missing properties (TS2741) and extra properties in literals (TS2353).
  • TypeScript uses structural typing: if the shape fits, the name doesn't matter.

Check yourself

10 questions. Every correct answer earns XP.

1 / 10
What does email?: string mean in an interface?