Typescript. Властивості доступні тільки для читання

У версії Typescript 2.0 був доданий модифікатор readonly. Властивостями поміченим модифікатором readonly значення може бути присвоєно тільки в момент ініціалізації, або в конструкторі того ж класу. Будь-які інші присвоювання значення заборонені.

Давайте подивимося на приклад. Тут представлений простий тип Point, описуваний двома властивостями, доступними тільки для читання:

type Point = {
  readonly x: number;
  readonly y: number;
};

Тепер ми можемо створити об’єкт являє собою початок координат, і ініціалізувати x і y багатозначно 0:

const origin: Point = { x: 0, y: 0 };

Однак, так як властивості x і y позначені readonly, ми не можемо змінити їх значення згодом:

// Error: Left-hand side of assignment expression
// cannot be a constant or read-only property
origin.x = 100;

Більш реалістичний приклад

Наведений вище приклад може здатися надуманим, давайте розглянемо наступну функцію:

function moveX(point: Point, offset: number): Point {
  point.x += offset;
  return point;
}

Функція moveX не повинна змінювати властивість xпереданого об’єкта point. Компілятор TypeScript обов’язково почне лаятися, якщо ви спробуєте це зробити, так як властивість позначено модифікатором readonly. Замість цього moveX повинна повертати новий об’єкт зі зміненими значеннями:

function moveX(p: Point, offset: number): Point {
  return {
    x: p.x + offset,
    y: p.y
  };
}

Тепер компілятор буде щасливий, більше немає спроб привласнити значення властивостям поміченим readonly. Ми створили новий об’єкт, який ініціалізується за оновленими значеннями.

Властивості класу, доступні тільки для читання

Ви також можете застосовувати модифікатор readonlyдо властивостей описаних в класі. Тут представлений клас Circle з readonly полем radius і властивістю area, яке непрямим чином реалізує доступність тільки для читання, тому що не має сетера:

class Circle {
    readonly radius: number;

    constructor(radius: number) {
        this.radius = radius;
    }

    get area() {
        return Math.PI * this.radius ** 2;
    }
}

Зверніть увагою, що area обчислюється за допомогою оператора піднесення до степеня. І radius, і area доступні ззовні класу для читання, тому що жоден з них не позначений як private, але не для запису:

const unitCircle = new Circle(1);
unitCircle.radius;  // 1
unitCircle.area;    // 3.141592653589793

// Error: Left-hand side of assignment expression
// cannot be a constant or read-only property
unitCircle.radius = 42;

// Error: Left-hand side of assignment expression
// cannot be a constant or read-only property
unitCircle.area = 42;

Доступні тільки для читання поля інтерфейсів

Поля інтерфейсів також можуть позначені, як доступні тільки для читання. Наприклад, тип ReadOnlyArray<T> запобігає запис значень в описані властивості:

interface ReadonlyArray<T> {
  readonly length: number;
  // ...
  readonly [n: number]: T;
}

Наступне присвоювання буде невалідним:

const primesBelow10: ReadonlyArray<number> = [2, 3, 5, 7];

// Error: Left-hand side of assignment expression
// cannot be a constant or read-only property
primesBelow10[4] = 11;

Readonly vs іммутабельність

Модифікатор readonly – це частина системи типів TypeScript. Він використовується тільки компілятором для перевірки незаконних присвоєнні значень. Як тільки TypeScript код компілюється в JavaScript таке поняття, як readonl піде геть.

Так як модифікатор readonly – це тільки артефакт при компіляції, він не є захистом від присвоювання значень під час виконання коду. Проте це ще одна особливість TypeScript, яка допоможе вам писати правильний код, залишивши компілятору роботу по перевірці ненавмисних присвоєнь значень.

Переклад статті “TypeScript 2.0: Read-Only Properties