Objects and unions

Optional and readonly properties

Express fields that may be absent and fields that should not be reassigned through a typed reference.

Object types support two useful modifiers. A question mark means a property may be absent. readonly prevents assignment through that typed reference:

type User = {
  readonly id: number
  nickname?: string
}

Both { id: 1 } and { id: 1, nickname: 'ada' } are valid User values. The type tells every reader of the code, and the compiler, that nickname is not guaranteed.

Reading an optional property

Reading nickname produces string | undefined, so narrow it before using string methods:

function label(user: User) {
  return user.nickname?.toUpperCase() ?? `User ${user.id}`
}

The optional chain calls toUpperCase() only when nickname exists. When it is absent, the expression evaluates to undefined, and ?? supplies the fallback. Call user.nickname.toUpperCase() without the ?. and the compiler answers:

'user.nickname' is possibly 'undefined'.

Do not mark a property optional only because creating it is inconvenient. Optional means callers and runtime code must handle its absence. Every read pays that cost with a check. If the value always exists after construction, make it required and fix the construction site instead.

What readonly protects

readonly stops this assignment during checking:

user.id = 2

The error is direct:

Cannot assign to 'id' because it is a read-only property.

That is exactly what you want for identifiers: an id should be set once when the record is created and never reassigned.

Know the limits, though. readonly does not freeze the object at runtime. JavaScript can still mutate the same object through another reference that allows writing — an alias typed as { id: number }, for example, writes freely. The modifier is a compile-time contract on one view of the object, not runtime protection like Object.freeze().

In practice that contract is still worth a lot. Most accidental mutations happen through the typed references your own code holds, and readonly catches those.

Exercise: add an optional bio and render it without using ! or as string.

Lesson completed

Take this course offline

Get every free book, course edition, and software download.

Get the download library →