Typescript: Модификаторы сопоставления типов (Mapping Modifiers)
При сопоставлении типов можно менять атрибуты свойств такие как неизменность (immutability) и необязательность (optionality). Делается это с помощью соответствующих модификаторов: readonly и ?.
Чтобы добавить или удалить эти модификаторы, можно использовать префиксы + или -. Если не использовать префикс, то подразумевается что модификатор будет добавлен, то есть по умолчанию префикс +.
Примеры использования модификаторов есть в Utility Types:
/**
* Делает все свойства типа `T` необязательными,
* то есть добавляет атрибут `?`.
*/
type Partial<T> = {
[P in keyof T]?: T[P];
};
/**
* Делает все свойства типа `T` обязательными,
* то есть удаляет атрибут `?`.
*/
type Required<T> = {
[P in keyof T]-?: T[P];
};
/**
* Делает все свойства типа `T` неизменяемыми,
* то есть добавляет атрибут `readonly`.
*/
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};Подобным образом можно написать и тип, который делает все свойства типа изменяемыми, то есть удаляет атрибут readonly:
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};Благодаря таким типам легче делать производные типы из уже имеющихся.
Например, в приложении может быть тип User для неавторизованного пользователя у которого все поля не обязательные:
type User = {
id?: string;
firstName?: string;
secondName?: string;
email?: string;
};Из него можно сделать авторизованного пользователя с помощью типа Required:
type AuthorizedUser = Required<DefaultUser>;Задание
Реализуйте функцию deepFreeze(), которая принимает на вход объект и делает его самого, его поля и все вложенные объекты неизменяемыми и возвращает этот объект.
Предполагается что поля объекта и поля вложенных объектов не содержат массивы, только простые типы данных и объекты.
const user = deepFreeze({
name: 'John',
password: '1q2w3e',
token: 'test',
});
user.name = 'Alex'; // Error: Cannot assign to 'name' because it is a read-only property.Нужно использовать встроенный в JavaScript метод Object.freeze().
Полезное
Typescript: Модификаторы сопоставления типов (Mapping Modifiers)
При сопоставлении типов можно менять атрибуты свойств такие как неизменность (immutability) и необязательность (optionality). Делается это с помощью соответствующих модификаторов: readonly и ?.
Чтобы добавить или удалить эти модификаторы, можно использовать префиксы + или -. Если не использовать префикс, то подразумевается что модификатор будет добавлен, то есть по умолчанию префикс +.
Примеры использования модификаторов есть в Utility Types:
/**
* Делает все свойства типа `T` необязательными,
* то есть добавляет атрибут `?`.
*/
type Partial<T> = {
[P in keyof T]?: T[P];
};
/**
* Делает все свойства типа `T` обязательными,
* то есть удаляет атрибут `?`.
*/
type Required<T> = {
[P in keyof T]-?: T[P];
};
/**
* Делает все свойства типа `T` неизменяемыми,
* то есть добавляет атрибут `readonly`.
*/
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};Подобным образом можно написать и тип, который делает все свойства типа изменяемыми, то есть удаляет атрибут readonly:
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};Благодаря таким типам легче делать производные типы из уже имеющихся.
Например, в приложении может быть тип User для неавторизованного пользователя у которого все поля не обязательные:
type User = {
id?: string;
firstName?: string;
secondName?: string;
email?: string;
};Из него можно сделать авторизованного пользователя с помощью типа Required:
type AuthorizedUser = Required<DefaultUser>;Задание
Реализуйте функцию deepFreeze(), которая принимает на вход объект и делает его самого, его поля и все вложенные объекты неизменяемыми и возвращает этот объект.
Предполагается что поля объекта и поля вложенных объектов не содержат массивы, только простые типы данных и объекты.
const user = deepFreeze({
name: 'John',
password: '1q2w3e',
token: 'test',
});
user.name = 'Alex'; // Error: Cannot assign to 'name' because it is a read-only property.Нужно использовать встроенный в JavaScript метод Object.freeze().
Полезное
Ваше упражнение проверяется по этим тестам
import { expect, expectTypeOf, test } from 'vitest';
import deepFreeze from './index';
test('deepFreeze', () => {
const obj = {
name: 'John',
age: 30,
location: {
city: 'York',
coordinates: {
lat: 53.958,
lon: -1.093,
},
},
};
const user = deepFreeze(obj);
expect(user).toEqual({
name: 'John',
age: 30,
location: {
city: 'York',
coordinates: {
lat: 53.958,
lon: -1.093,
},
},
});
expect(() => {
// @ts-expect-error Cannot assign read-only property.
user.age = 20;
}).toThrow();
expect(() => {
// @ts-expect-error Cannot assign nested read-only property.
user.location.city = 'London';
}).toThrow();
expectTypeOf(user).toExtend<
Readonly<{
name: string;
age: number;
location: Readonly<{
city: string;
coordinates: Readonly<{
lat: number;
lon: number;
}>;
}>;
}>
>();
});Решение учителя откроется через:
20:00
