Typescript. Свойства доступные только для чтения

habr.png

Перевод. Оригинал по ссылке.


В версии 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 предотвращает запись значений в описанные свойства:


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


Следующее присваивание будет невалидным:


const primesBelow10: ReadonlyArray = [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 такое понятие, как readonly уходит прочь. Не поленитесь поиграть с маленьким примером, чтобы посмотреть во что компилируются свойства доступные только для чтения.


Так как модификатор readonly — это только артефакт при компиляции, он не является защитой от присваивания значений во время исполнения кода. Тем не менее это ещё одна особенность TypeScript, которая поможет вам писать правильный код, оставив компилятору работу по проверке непреднамеренных присвоений значений.

© Habrahabr.ru