TypeScript Objects

Objects & Interfaces

Describing the shape of objects is TypeScript's bread and butter. Interfaces and type aliases both do it, and structural typing decides what counts as a match.

TypeScript 5 ✓ Core Concepts 3 Topics
01

interface vs type alias

Both describe an object's shape and are mostly interchangeable. interface can be re-opened and extended; type can express unions and other shapes an interface cannot.

TypeScript — interface & type
interface User {
  name: string;
  age: number;
}

// type alias — same shape
type Point = { x: number; y: number };

// interface: extend and merge
interface Admin extends User { role: string; }

// type: unions and things interface can't do
type ID = string | number;
type Pair = [number, number];     // tuple
interfacetype
Object shapesYesYes
Unions / tuplesNoYes
ExtendextendsIntersection &
Declaration mergingYes (re-open)No
Rule of thumb: use interface for object shapes and public APIs (it merges and reads cleanly), and type when you need unions, tuples, or mapped/conditional types. Teams often standardise on one for consistency.
02

Optional, readonly & Index Signatures

TypeScript — Property Modifiers
interface Config {
  readonly id: string;      // can't be reassigned after creation
  name: string;
  timeout?: number;         // optional — number | undefined
  [key: string]: unknown;    // index signature — arbitrary extra keys
}

const c: Config = { id: "a1", name: "prod" };
// c.id = "a2";           // Error: readonly property
c.timeout;                // number | undefined — must handle undefined
c.anything = 42;          // allowed via index signature

// readonly arrays and tuples
const nums: readonly number[] = [1, 2, 3];
// nums.push(4);          // Error: push doesn't exist on readonly array
readonly is a compile-time guarantee only. It stops you from reassigning, but the underlying JavaScript object is still mutable at runtime. It's not Object.freeze.
03

Structural Typing

TypeScript uses structural typing ("duck typing"): a value is compatible with a type if it has the required shape, regardless of whether it was declared with that type's name. Java and C++ use nominal typing, where names must match.

TypeScript — Shape, Not Name
interface Named { name: string; }

function greet(x: Named) { return `Hi ${x.name}`; }

// this object was never declared as Named, but it fits the shape
const dog = { name: "Rex", breed: "Lab" };
greet(dog);              // OK — has a string 'name', extra props ignored

// object literals get "excess property checks" when passed directly
// greet({ name: "x", breed: "y" });  // Error: 'breed' not in Named
Structural typing makes TypeScript flexible: anything with the right shape works, no explicit implements needed. The exception is excess property checks on object literals passed directly to a function, which catch typos in optional props.

Quick Quiz

1. Which can express a union type?
2. Which supports declaration merging (re-opening)?
3. readonly on a property is enforced…
4. TypeScript's type compatibility is based on…
5. An index signature [key: string]: unknown allows…