-
Notifications
You must be signed in to change notification settings - Fork 89
Add 35-mapping-modifiers #305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
test: | ||
@ test.sh |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
--- | ||
|
||
name: Модификаторы сопоставления типов (Mapping Modifiers) | ||
theory: | | ||
|
||
При сопоставлении типов можно менять атрибуты свойств такие как неизменность (immutability) и необязательность (optionality). Делается это с помощью соответствующих модификаторов: `readonly` и `?`. | ||
|
||
Чтобы добавить или удалить эти модификаторы, можно использовать префиксы `+` или `-`. Если не использовать префикс, то подразумевается что модификатор будет добавлен, то есть по умолчанию префикс `+`. | ||
|
||
Примеры использования модификаторов есть в Utility Types: | ||
|
||
```typescript | ||
/** | ||
* Делает все свойства типа `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`: | ||
|
||
```typescript | ||
type Mutable<T> = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. давай также покажем как используется |
||
-readonly [P in keyof T]: T[P]; | ||
}; | ||
``` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. нужно добавить небольшой "рекап" - что мы изучили и как оно нам может пригодиться |
||
instructions: | | ||
|
||
Реализуйте функцию `deepFreeze()`, которая принимает на вход объект и делает его самого, его поля и все вложенные объекты неизменяемыми и возвращает этот объект. | ||
|
||
```typescript | ||
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()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze). | ||
|
||
tips: | ||
- | | ||
[Официальная документация Mapped Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html) | ||
- | | ||
[Официальная документация Mapping Modifiers](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers) | ||
- | | ||
[Официальная документация Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype) | ||
- | | ||
[Официальная документация Required](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) | ||
- | | ||
[Официальная документация Readonly](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// BEGIN | ||
type DeepReadonly<T> = { | ||
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. а что делать с массивами? |
||
}; | ||
|
||
const deepFreeze = <T extends object>(obj: T): DeepReadonly<T> => { | ||
Object.freeze(obj); | ||
|
||
Object.values(obj).forEach((value) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. мы стараемся писать имутабельный код |
||
if (typeof value === 'object' && value !== null) { | ||
deepFreeze(value); | ||
} | ||
}); | ||
|
||
return obj; | ||
}; | ||
// END | ||
|
||
export default deepFreeze; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. лишняя строчка |
||
Реализуйте функцию `deepFreeze()`, которая принимает на вход объект и делает его самого, его поля и все вложенные объекты неизменяемыми и возвращает этот объект. | ||
|
||
```typescript | ||
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()](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
При сопоставлении типов можно менять атрибуты свойств такие как неизменность (immutability) и необязательность (optionality). Делается это с помощью соответствующих модификаторов: `readonly` и `?`. | ||
|
||
Чтобы добавить или удалить эти модификаторы, можно использовать префиксы `+` или `-`. Если не использовать префикс, то подразумевается что модификатор будет добавлен, то есть по умолчанию префикс `+`. | ||
|
||
Примеры использования модификаторов есть в Utility Types: | ||
|
||
```typescript | ||
/** | ||
* Делает все свойства типа `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`: | ||
|
||
```typescript | ||
type Mutable<T> = { | ||
-readonly [P in keyof T]: T[P]; | ||
}; | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
name: Модификаторы сопоставления типов (Mapping Modifiers) | ||
tips: | ||
- > | ||
[Официальная документация Mapped | ||
Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html) | ||
- > | ||
[Официальная документация Mapping | ||
Modifiers](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#mapping-modifiers) | ||
- > | ||
[Официальная документация | ||
Partial](https://www.typescriptlang.org/docs/handbook/utility-types.html#partialtype) | ||
- > | ||
[Официальная документация | ||
Required](https://www.typescriptlang.org/docs/handbook/utility-types.html#requiredtype) | ||
- > | ||
[Официальная документация | ||
Readonly](https://www.typescriptlang.org/docs/handbook/utility-types.html#readonlytype) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import * as ta from 'type-assertions'; | ||
|
||
import deepFreeze from './index'; | ||
|
||
test('deepFreeze', () => { | ||
const obj = { | ||
name: 'John', | ||
age: 30, | ||
location: { | ||
city: 'York', | ||
coordinates: { | ||
lat: 53.958, | ||
lon: -1.093, | ||
}, | ||
}, | ||
}; | ||
|
||
expect(deepFreeze(obj)).toEqual({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. хорошо бы проверить что также сама логика валидная и мы не можем поменять свойства |
||
name: 'John', | ||
age: 30, | ||
location: { | ||
city: 'York', | ||
coordinates: { | ||
lat: 53.958, | ||
lon: -1.093, | ||
}, | ||
}, | ||
}); | ||
|
||
const user = deepFreeze(obj); | ||
|
||
ta.assert<ta.Equal<typeof user, Readonly<{ | ||
name: string, | ||
age: number, | ||
location: Readonly<{ | ||
city: string, | ||
coordinates: Readonly<{ | ||
lat: number, | ||
lon: number, | ||
}>, | ||
}>, | ||
}>>>(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Давай подумаем над примером из реальной жизни