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
предотвращает запись значений в описанные свойства:
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
, которая поможет вам писать правильный код, оставив компилятору работу по проверке непреднамеренных присвоений значений.