TypeScript Object Types

Object types describe the shape of an object's properties, letting TypeScript check that the right keys and value types are present wherever that object is used.

Defining an Object Type

An object type lists property names and the type of value each property should hold. You can write it inline or extract it into a reusable type alias or interface.

Inline vs Named Object Types

// Inline object type
function printUser(user: { name: string; age: number }) {
  console.log(`${user.name} is ${user.age}`);
}

// Named, reusable object type
type User = {
  name: string;
  age: number;
};

function printUserNamed(user: User) {
  console.log(`${user.name} is ${user.age}`);
}

Optional and Readonly Properties

Properties can be marked optional with a question mark, meaning the key may be omitted entirely. Properties can also be marked readonly, meaning they can be set when the object is created but not reassigned afterward.

Optional and Readonly Members

type Product = {
  readonly id: string;
  name: string;
  description?: string;
};

const item: Product = { id: "p1", name: "Keyboard" };

// item.id = "p2"; // Error: Cannot assign to 'id' because it is a read-only property
item.description = "Mechanical keyboard"; // fine, optional property being set
Note: Use readonly for properties like ids or createdAt timestamps that should never change after an object is constructed — it catches accidental mutation bugs at compile time.

Nested Object Types

Object types can contain other object types as property values, letting you model structured, nested data such as an address inside a user record.

Nesting Object Types

type Address = {
  street: string;
  city: string;
  postalCode: string;
};

type Customer = {
  name: string;
  address: Address;
};

const customer: Customer = {
  name: "Jordan",
  address: { street: "12 Elm St", city: "Austin", postalCode: "73301" },
};

Index Signatures

Sometimes you don't know property names in advance, only their pattern — for example, a dictionary of scores keyed by player name. Index signatures let you type these dynamic-key objects.

Index Signature Example

type ScoreBoard = {
  [playerName: string]: number;
};

const scores: ScoreBoard = {};
scores["Amara"] = 10;
scores["Lee"] = 7;
// scores["Lee"] = "seven"; // Error: must be a number
  • Use plain object types for known, fixed sets of properties.
  • Use optional (?) for properties that may be absent.
  • Use readonly for properties that must not change after creation.
  • Use index signatures for dictionary-like, dynamically-keyed objects.
  • Prefer extracting a type alias once an object shape is used in more than one place.
Note: TypeScript's object types are structural, not nominal — any object with matching properties satisfies the type, even if it wasn't explicitly declared as that type.

Object Types vs Excess Property Checks

ScenarioBehavior
Assigning a variable that already has extra propertiesAllowed (structural typing)
Passing an object literal directly with extra propertiesError (excess property check)
Passing an object literal through a variable firstAllowed

Realistic Use Case: Typing an API Response

Object types shine when modeling data coming back from an API, ensuring every place in your code that consumes the response agrees on its shape.

Typing a Fetch Response

type ApiUser = {
  id: number;
  username: string;
  email: string;
  isActive?: boolean;
};

async function fetchUser(id: number): Promise<ApiUser> {
  const response = await fetch(`/api/users/${id}`);
  const data: ApiUser = await response.json();
  return data;
}

Exercise: TypeScript Object Types

How do you annotate a parameter as an object with a name string and age number?