TypeScript: Readonly and Optional Properties in Interface

Updated: January 7, 2024 By: Guest Contributor Post a comment


In the grand and fertile expanse that is TypeScript, interfaces stand as declarations of the shape that our objects shall assume. Herein, we shall delve into how readonly and optional properties in interfaces can be utilized to craft a codebase both immutable when necessary, and lenient whenever allowance can be made.

Understanding Readonly Properties

Consider a pact carved in stone, unyielding and tireless; such is the premise of readonly properties. Once they are set, like the course of the Mississippi river, they are not to be redirected – at least, not within the bound scope of TypeScript’s type safety policies. Let’s illuminate:

interface Person {
    readonly name: string;
    readonly birthDate: Date;
let mark: Person = {name: 'Samuel Clemens', birthDate: new Date()};
mark.name = 'Mark Twain'; // Compilation error: cannot reassign a readonly property

Onward, to optional properties, akin to a steamboat’s stops along the river; not always predictable, but always beneficial when they appear.

Incorporating Optional Properties

Just as a tall tale might involve elements of truth interwoven with charisma-driven exaggeration, TypeScript interfaces admit days when properties are declared but their provision is not guaranteed, signified by a single ‘?’.

interface Story {
    title: string;
    author: string;
    year?: number;
let ghostStory: Story = {title: 'The Phantom’s Tollbooth', author: 'A. B. Author'}; // Year is not required

The drama unfolds as we weave the readonly and optional annotations into one, morphing our interfaces into structures with a twang of both certainty and pleasant unforeseeable adventures.

Combining Readonly and Optional

interface Steamboat {
    readonly name: string;
    launchYear?: number;
let theSprague: Steamboat = {name: 'Sprague'}; // Setting of name suffices

Press further on this journey and discover the interplay of inheritance among interfaces; a veritable Mississippi of possibilities.

Extension of Interfaces

Streamline your TypeScript typology like the mighty river cutting through the landscape, by extending interfaces, inheriting the traits of existing statutes embodied in interfaces, thus augmenting them with lines of your own authorship.

interface NamedObject {
    readonly id: number;
    name: string;

interface Book extends NamedObject {
    author: string;
    year?: number;

To penquire into the conditional rendering of properties, we must handle the utility types that TypeScript, in its cunning, provides.

Using Utility Types with Readonly and Optional

Tales of utility types abound, aiding scribes like a lantern in the night; they transform our interfaces in situ, exalting them to the virtues of conditions they must cherish or shed as the context necessitates.

interface Adventure {
    name: string;
    year: number;

const novel: Readonly = {name: 'A Tale Unwinding', year: 1881};
novel.year = 2021; // Error: year is a readonly property in this context

const incompleteNovel: Partial = {name: 'Unfinished Symphony'}; // year is not necessary

Alas, I have seen you stern and unforgiving when wrought upon by conundrums most challenging; but let’s bring up one undeniably engrossing: advanced manipulations of readonly and optional properties, much like the plotting of a novel’s most suspenseful twist.

Advanced Practices

Expect an odyssey deep into the mapping of types where types themselves become materialized through conditional musing and the employment of mapped types.

// Define a mutable type from a readonly interface
type Mutable = {
    -readonly [P in keyof T]: T[P];

// Make Story's properties mutable
type EditableStory = Mutable;

And thus, equipped with such understanding, a typographer ventures into the wide open of TypeScript majesty, undaunted and prepared for every narrative twist it lays before.


In our winding down, recollect the resonant echo of readonly permanence and the silent tap dance of optionality; merging immutable and evanescent tales within the sturdy lupine frames of TypeScript interfaces. Embrace the intricate guild of ReadOnly and Optional properties, and mark your voyage into the TypeScript territories with the deliberation of a riverboat captain charting a careful passage along the Mississippi.