Object Types

Learn how to model object shapes in TypeScript using property types, optional fields, readonly properties, and nested structures. Object typing is the foundation of reliable domain models and API contracts.

On this page

Why object types matter

Most real-world TypeScript code is about objects: API responses, database records, configuration objects, UI props, and domain models. Object types define the shape of data and prevent the most common production failures: missing fields, incorrect types, and unsafe assumptions when data evolves.

Basic object type syntax

You can type an object by defining its required properties and their types.

let user: { id: number; name: string } = {
  id: 1,
  name: "Yusuf"
};

If a required property is missing or has the wrong type, TypeScript reports an error at compile time.

Optional properties

Not every field exists in every scenario. Use ? for optional properties. This forces you to handle the absence of the value safely.

type Profile = {
  id: number;
  name: string;
  avatarUrl?: string;
};

const p: Profile = { id: 1, name: "Elif" };

Readonly properties

Some properties should never change after creation, such as database primary keys. Use readonly to prevent accidental mutation.

type User = {
  readonly id: number;
  name: string;
};

const u: User = { id: 1, name: "Yusuf" };

// u.id = 2; // Error
u.name = "Yusuf A."; // OK

Nested object structures

Production data is often nested. Object types can model nested structures clearly and safely.

type Post = {
  id: number;
  title: string;
  author: {
    id: number;
    name: string;
  };
};

const post: Post = {
  id: 10,
  title: "Type Safety",
  author: { id: 1, name: "Ozan" }
};

Index signatures for dynamic keys

Sometimes objects act like dictionaries where keys are not known ahead of time. Index signatures allow safe dynamic access.

type StringMap = {
  [key: string]: string;
};

const headers: StringMap = {
  "content-type": "application/json",
  "accept": "application/json"
};

Use index signatures carefully. They can make models too permissive if overused.

Excess property checks

TypeScript protects you from accidentally passing extra properties when using object literals. This is valuable for catching typos and API contract drift.

type Config = { debug: boolean };

const cfg: Config = { debug: true, debg: true };
// Error: 'debg' does not exist in type Config

Objects as contracts between layers

In production systems, object types should represent contracts between layers: controllers, services, database access, and UI components. Keeping these contracts explicit makes refactoring and collaboration significantly safer.

Prefer named types for reusable models

Inline object types are fine for small examples, but reusable models should be defined as named types (type aliases or interfaces). This improves readability and prevents duplication.

Common mistakes

  • Marking too many fields as optional and losing safety.
  • Using broad index signatures that hide invalid keys.
  • Using any for objects instead of modeling structure.
  • Mixing domain models and transport models without clear boundaries.

Production guidance

  • Model required fields explicitly and keep optional fields meaningful.
  • Use readonly for identifiers and immutable properties.
  • Use named types for shared contracts across files.
  • Keep dictionary-like objects constrained and intentional.

What’s next

Now that you can model object shapes safely, the next step is typing functions more deeply: parameters, return types, and patterns for predictable APIs.