TypeScript marks optional properties/parameters with ?, immutable properties with readonly, and supports default parameter values. These express intent and prevent misuse.
interface Config { timeout?: number } makes timeout optional (its type becomes number | undefined). A function param can be optional (fn(x?: string)) or have a default (fn(x = 30)) — a default implies optional. readonly properties (readonly id: number) can be set at construction but not reassigned, protecting invariants. Optional chaining (obj?.prop) and nullish coalescing (?? default) pair naturally with optional/undefined values. For arrays, ReadonlyArray<T> or readonly T[] prevents mutation. These features let types document which fields are required and which are safe defaults.
interface RequestOptions { url: string; method?: string; timeout?: number } lets a test helper require url but default method/timeout, and readonly baseUrl protects a config constant from accidental reassignment.
You mark a property readonly id: number but a test still mutates the nested object it points to. Why doesn't readonly stop that?