Basic

Interfaces and Object Types

Describe the shape of objects with interfaces and type aliases for reusable contracts.

What you will see

open open

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

An interface names an object's shape; the compiler checks objects against it, then drops the declaration entirely. Combine interfaces with `?` optional and `readonly` modifiers.

1

Defining an interface

interface User { name: string; age: number; } function show(u: User) { console.log(u.name, u.age); } show({ name: "Ada", age: 30 });

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Ada 30
2

Optional and readonly properties

interface Config { host: string; port?: number; readonly apiKey: string; } const cfg: Config = { host: "localhost", apiKey: "secret" }; console.log(cfg.host, cfg.port);

Before you run it, say out loud what it will print. Then open the answer.

What it prints
localhost undefined
3

Type aliases for unions

type ID = string | number; type Status = "open" | "closed"; function resolve(id: ID): Status { return "open"; } console.log(resolve(42), resolve("x"));

Before you run it, say out loud what it will print. Then open the answer.

What it prints
open open

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

An interface declares a shape; an object literal must satisfy it; the compiler checks each property.
1 Declare interface with property names and types
↓
2 Create an object literal -> compiler checks against shape
↓
3 Pass object where interface is expected -> structural match
↓
4 Mismatched or missing property -> compile error
Why this works
Structural typing

TypeScript uses structural (duck) typing: two objects are compatible if they have the same shape, regardless of name:

interface A { x: number; y: number; }
interface B { x: number; y: number; }
const a: A = { x: 1, y: 2 };
const b: B = a;   // OK: same shape, names don't matter

This makes types composable and flexible, matching on structure rather than declared identity.

When you have a choice

interface vs type

Both describe object shapes. Prefer interface for object contracts because it can be extended via declaration merging:

interface User { name: string; }
interface User { age: number; }  // merges into { name; age }

Use type for unions, tuples, or computed shapes that interfaces cannot express. In practice they overlap heavily and either is fine.

Examples

Defining an interface

Describing object shapes

interface User {
  name: string;
  age: number;
}
function show(u: User) {
  console.log(u.name, u.age);
}

An interface names a contract: any object passed as User must have a name string and age number.

Optional and readonly properties

Partial and immutable fields

interface Config {
  host: string;
  port?: number;          // optional
  readonly apiKey: string; // cannot be reassigned
}
const cfg: Config = { host: "localhost" };

? marks a property optional; readonly prevents reassignment after creation. Both are compile-time checks only.

Type aliases for unions

Type aliases

type ID = string | number;
type Status = "open" | "closed";
function resolve(id: ID): Status {
  return "open";
}

type aliases name any type, including unions. "open" | "closed" is a literal union that only accepts those exact strings.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Typed Functions
Previous Lesson
Typed Functions
Next Lesson
Unions and Type Guards
Unions and Type Guards →