webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Tooling
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Forms
  12. 12Data and backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animations
  16. 16Testing
  17. 17Architecture
TypeScript · Lesson 2 of 6

Objects: type and interface

Object shapes, optional and readonly fields, Record, type vs interface.

Updated

What typing an object means

You describe the object's shape: which keys it has and what type each value is. TS then checks that every object you use matches the shape.

type Product = {
  id: number
  name: string
  price: number
  tags?: string[]          // optional — may be missing
  readonly sku: string     // can't be changed after creation
}

const p: Product = { id: 1, name: 'Laptop', price: 4000, sku: 'LP-1' }
p.sku = 'X'                // ✗ readonly
p.color                    // ✗ doesn't exist on Product

type vs interface — differences and when

Both describe the shape of an object. In 90% of cases they're interchangeable.

type interface
Objects ✓ ✓
Unions, tuples, primitives, functions ('a' | 'b') ✓ ✗
Extending type B = A & { x: number } interface B extends A { x: number }
Declaration merging (two declarations with the same name combine) ✗ ✓
Error messages sometimes longer sometimes clearer

A practical recommendation: type by default (works for everything), interface when you write a library others will extend or when the team prefers it. What matters is being consistent.

Optional and readonly properties

type User = {
  id: number
  email: string
  nickname?: string            // string | undefined
  readonly createdAt: Date
}

function displayName(user: User) {
  return user.nickname ?? user.email   // TS forces you to handle the missing case
}

Dictionaries: index signatures and Record

When the keys aren't known upfront:

type Prices = { [productId: string]: number }
type Prices2 = Record<string, number>            // equivalent, more readable

const stock: Record<'us' | 'ca', number> = { us: 10, ca: 2 }   // fixed keys from a union

Nested and composed types

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

type Timestamps = { createdAt: Date; updatedAt: Date }
type Post = { title: string } & Timestamps      // an intersection: has everything from both

Structural typing

TS compares objects by shape, not by name: any object that has the required fields is accepted.

type Point = { x: number; y: number }
const p3 = { x: 1, y: 2, z: 3 }
const p: Point = p3          // ✓ it has x and y — the extra field doesn't matter

(The exception: an object literal written directly with extra fields gives an error — the "excess property check" — to catch typos.)

Summary

  • You type the object's shape; ? optional, readonly unchangeable.
  • type by default; interface for extending / libraries.
  • Record<K, V> for dictionaries; & for combining.

Official sources

Exercises

Was this page helpful?

One tap — no account needed.