Skip to content

Commit b310292

Browse files
committed
Add 35-mapping-modifiers
1 parent 30d7326 commit b310292

File tree

7 files changed

+206
-0
lines changed

7 files changed

+206
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test:
2+
@ test.sh
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
3+
name: Модификаторы сопоставления типов (Mapping Modifiers)
4+
theory: |
5+
6+
При сопоставлении типов можно менять атрибуты свойств такие как неизменность (immutability) и необязательность (optionality). Делается это с помощью соответствующих модификаторов: `readonly` и `?`.
7+
8+
Чтобы добавить или удалить эти модификаторы, можно использовать префиксы `+` или `-`. Если не использовать префикс, то подразумевается что модификатор будет добавлен, то есть по умолчанию префикс `+`.
9+
10+
Примеры использования модификаторов есть в Utility Types:
11+
12+
```typescript
13+
/**
14+
* Делает все свойства типа `T` необязательными,
15+
* то есть добавляет атрибут `?`.
16+
*/
17+
type Partial<T> = {
18+
[P in keyof T]?: T[P];
19+
};
20+
21+
/**
22+
* Делает все свойства типа `T` обязательными,
23+
* то есть удаляет атрибут `?`.
24+
*/
25+
type Required<T> = {
26+
[P in keyof T]-?: T[P];
27+
};
28+
29+
/**
30+
* Делает все свойства типа `T` неизменяемыми,
31+
* то есть добавляет атрибут `readonly`.
32+
*/
33+
type Readonly<T> = {
34+
readonly [P in keyof T]: T[P];
35+
};
36+
```
37+
38+
Подобным образом можно написать и тип, который делает все свойства типа изменяемыми, то есть удаляет атрибут `readonly`:
39+
40+
```typescript
41+
type Mutable<T> = {
42+
-readonly [P in keyof T]: T[P];
43+
};
44+
```
45+
46+
instructions: |
47+
48+
Реализуйте функцию `deepFreeze()`, которая принимает на вход объект и делает его самого, его поля и все вложенные объекты неизменяемыми и возвращает этот объект.
49+
50+
```typescript
51+
const user = deepFreeze({
52+
name: 'John',
53+
password: '1q2w3e',
54+
token: 'test',
55+
});
56+
57+
user.name = 'Alex'; // Error: Cannot assign to 'name' because it is a read-only property.
58+
```
59+
60+
Нужно использовать встроенный в JavaScript метод [Object.freeze()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze).
61+
62+
tips:
63+
- |
64+
[Официальная документация Mapped Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)
65+
- |
66+
[Официальная документация Mapping Modifiers](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers)
67+
- |
68+
[Официальная документация Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype)
69+
- |
70+
[Официальная документация Required](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype)
71+
- |
72+
[Официальная документация Readonly](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// BEGIN
2+
type DeepReadonly<T> = {
3+
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
4+
};
5+
6+
const deepFreeze = <T extends object>(obj: T): DeepReadonly<T> => {
7+
Object.freeze(obj);
8+
9+
Object.values(obj).forEach((value) => {
10+
if (typeof value === 'object' && value !== null) {
11+
deepFreeze(value);
12+
}
13+
});
14+
15+
return obj;
16+
};
17+
// END
18+
19+
export default deepFreeze;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
Реализуйте функцию `deepFreeze()`, которая принимает на вход объект и делает его самого, его поля и все вложенные объекты неизменяемыми и возвращает этот объект.
3+
4+
```typescript
5+
const user = deepFreeze({
6+
name: 'John',
7+
password: '1q2w3e',
8+
token: 'test',
9+
});
10+
11+
user.name = 'Alex'; // Error: Cannot assign to 'name' because it is a read-only property.
12+
```
13+
14+
Нужно использовать встроенный в JavaScript метод [Object.freeze()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze).
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
При сопоставлении типов можно менять атрибуты свойств такие как неизменность (immutability) и необязательность (optionality). Делается это с помощью соответствующих модификаторов: `readonly` и `?`.
2+
3+
Чтобы добавить или удалить эти модификаторы, можно использовать префиксы `+` или `-`. Если не использовать префикс, то подразумевается что модификатор будет добавлен, то есть по умолчанию префикс `+`.
4+
5+
Примеры использования модификаторов есть в Utility Types:
6+
7+
```typescript
8+
/**
9+
* Делает все свойства типа `T` необязательными,
10+
* то есть добавляет атрибут `?`.
11+
*/
12+
type Partial<T> = {
13+
[P in keyof T]?: T[P];
14+
};
15+
16+
/**
17+
* Делает все свойства типа `T` обязательными,
18+
* то есть удаляет атрибут `?`.
19+
*/
20+
type Required<T> = {
21+
[P in keyof T]-?: T[P];
22+
};
23+
24+
/**
25+
* Делает все свойства типа `T` неизменяемыми,
26+
* то есть добавляет атрибут `readonly`.
27+
*/
28+
type Readonly<T> = {
29+
readonly [P in keyof T]: T[P];
30+
};
31+
```
32+
33+
Подобным образом можно написать и тип, который делает все свойства типа изменяемыми, то есть удаляет атрибут `readonly`:
34+
35+
```typescript
36+
type Mutable<T> = {
37+
-readonly [P in keyof T]: T[P];
38+
};
39+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name: Модификаторы сопоставления типов (Mapping Modifiers)
2+
tips:
3+
- >
4+
[Официальная документация Mapped
5+
Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)
6+
- >
7+
[Официальная документация Mapping
8+
Modifiers](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers)
9+
- >
10+
[Официальная документация
11+
Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype)
12+
- >
13+
[Официальная документация
14+
Required](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype)
15+
- >
16+
[Официальная документация
17+
Readonly](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import * as ta from 'type-assertions';
2+
3+
import deepFreeze from './index';
4+
5+
test('deepFreeze', () => {
6+
const obj = {
7+
name: 'John',
8+
age: 30,
9+
location: {
10+
city: 'York',
11+
coordinates: {
12+
lat: 53.958,
13+
lon: -1.093,
14+
},
15+
},
16+
};
17+
18+
expect(deepFreeze(obj)).toEqual({
19+
name: 'John',
20+
age: 30,
21+
location: {
22+
city: 'York',
23+
coordinates: {
24+
lat: 53.958,
25+
lon: -1.093,
26+
},
27+
},
28+
});
29+
30+
const user = deepFreeze(obj);
31+
32+
ta.assert<ta.Equal<typeof user, Readonly<{
33+
name: string,
34+
age: number,
35+
location: Readonly<{
36+
city: string,
37+
coordinates: Readonly<{
38+
lat: number,
39+
lon: number,
40+
}>,
41+
}>,
42+
}>>>();
43+
});

0 commit comments

Comments
 (0)