Skip to content

Commit 3565019

Browse files
committed
book(исправление): fix toc
fix toc
1 parent f821ecc commit 3565019

File tree

2 files changed

+92
-4
lines changed

2 files changed

+92
-4
lines changed

book/ru/chapters/034.(Типы) Обобщения (Generics)/content.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,3 +703,87 @@ class Identifier<T> {
703703
}
704704
}
705705
`````
706+
707+
## Модификаторы вариантности параметров типа in и out
708+
709+
Идентификация данных осуществляется при помощи типов и предназначена для предотвращения попадания в операции неподходящих для них значений. Каждая операция имеет свое низкоуровневое описание содержащее, в том числе и тип, к которому должно принадлежать пригодное для неё значение. Сверка типа значения с этим типом называется процессом выявления совместимости. Совместимость осуществляется по правилам вариантности, которые бывают четырех видов. Но прежде, чем рассмотреть каждый из них, ненадолго отвлечемся на _TypeScript_.
710+
Поскольку _TypeScript_ реализует _структурную типизацию_, тип проще всего представить в виде обычного листка бумаги, который может содержать имена (идентификаторы) ассоциированные с какими-либо другими типами. Идентификатор + ассоциированный с ним тип = признак типа. Именно на основе этих признаков и осуществляется процесс выявления совместимости речь о которой пойдет сразу после того освещения ещё одной очень простой темы - иерархии наследования.
711+
Представляя иерархию наследования в голове сразу вырисовывается картина из мира номинативной типизации, что неосознанно выбивает из колеи структурной. Поэтому сразу стоит сосредоточиться на интересующей нас детали - логическом обозначении иерархических отношений. Дело в том, что иерархия направлена сверху вниз, а значит более базовый тип расположен выше, чем его подтип. Таким образом, в логических выражениях представляющих иерархию базовые типы обозначаются, как большие (`>`) по отношению к своим подтипам. И наоборот. То есть, `SuperType > SubType` и `SubType < SuperType`. Но упомяну ещё раз, в структурной типизации нет понятия иерархия наследования, поскольку при сравнении берутся в расчет признаки типов, а не ссылки (`ref`). Но чтобы не забивать особо голову просто возьмем за правило, что тип, который обладает всеми признаками другого типа и кроме этого содержит дополнительные, будет считаться подтипом, а значит, в логических выражениях будет обозначаться меньшим (`<`).
712+
713+
`````ts
714+
interface A {
715+
f0: boolean;
716+
}
717+
interface B {
718+
f0: boolean;
719+
f1: number;
720+
}
721+
interface С {
722+
f0: boolean;
723+
f1: number;
724+
}
725+
726+
// A > B или B < A
727+
// A > C или C < A
728+
// B = C или C = B
729+
`````
730+
731+
Это очень просто и это знают все, но повторить все равно стоило, так как именно логические выражения нам помогут разобраться в количестве видов вариантов совместимости. Теперь, на основе полученной информации давайте рассмотрим варианты по которым может происходить проверка на совместимость.
732+
733+
И так, вариантов всего четыре и каждый из них имеет собственное название. Но чтобы было более понятно рассмотрим сценарий, когда переменной принадлежащей к типу `A` может быть присвоено значение с типом `B`.
734+
735+
`Ковариантность` предполагает, что проверка на совместимость завершится успехом в случаи, когда `B < A` или `B = A` (в номинативной типизации `B` подтип `A` ). `Контрвариантность` предполагает, что `B > A` или `B = A` (в номинативной бы это звучало, как базовый тип можно совместим с подтипом или самим собой, но не наоборот). `Инвариантность`, это когда совместимы исключительно при условии `B = A`. `Бивариантность` подразумевает `B < A`, `B > A` или `B = A`, то есть - все предыдущие варианты в одном.
736+
737+
А теперь к сути дела. В _TypeScript_ все типы проверяются на совместимость по ковариантным правилам, за исключением параметров функций, которые контрвариантны. Поскольку различные правила на сложных рекурсивных типах требуют дорогостоящие вычисления, _TypeScript_ реализует механизм явного аннотирования параметров типа при с помощью необязательных модификаторов `in` и `out`.
738+
739+
`in` указывает, что параметр типа ковариантен, а `out` контрвариантен. Но стоит сделать акцент на том, что с помощью этих модификаторов невозможно изменить правила по которым _TypeScript_ производит вычисления совместимости, а можно лишь их конкретизировать.
740+
741+
`````ts
742+
type Setter<T> = (param: T) => void;
743+
type Getter<T> = () => T;
744+
745+
/**
746+
* Стандартный код.
747+
* При сравнении двух сеттеров параметры в сигнатуре будут проверятся по контрвариантным правилам, а для геттеров возвращаемые типы по ковариантным.
748+
*/
749+
`````
750+
`````ts
751+
type Setter<in T> = (param: T) => void;
752+
type Getter<out T> = () => T;
753+
754+
/**
755+
* [Код с модификаторами]
756+
* Правила будут идентичны предыдущему примеру. Разница лишь в явной конкретизации.
757+
*/
758+
`````
759+
`````ts
760+
type Setter<out T> = (param: T) => void; // [0]
761+
type Getter<in T> = () => T; // [1]
762+
763+
/**
764+
* [Код с модификаторами]
765+
* К тому же, нельзя изменить поведение, то есть - нельзя поменять модификаторы местами!
766+
*/
767+
768+
/**
769+
* [0]
770+
* Type 'Setter<sub-T>' is not assignable to type 'Setter<super-T>' as implied by variance annotation.
771+
* Types of parameters 'param' and 'param' are incompatible.
772+
* Type 'super-T' is not assignable to type 'sub-T'.ts(2636)
773+
*/
774+
775+
/**
776+
* [1]
777+
* Type 'Getter<super-T>' is not assignable to type 'Getter<sub-T>' as implied by variance annotation.
778+
* Type 'super-T' is not assignable to type 'sub-T'.ts(2636)
779+
*/
780+
`````
781+
782+
Проще всего воспринимать эти модификаторы, как указание на то, что тип будет использоваться во входных параметрах (`<in T>`) или выходных (`<out T>`) или и то и другое одновременно `<in out T>`.
783+
784+
`````ts
785+
/**
786+
* Указание на то, что тип используется во входных и в выходных параметрах.
787+
*/
788+
type Func<in out T> = (param: T) => T;
789+
`````

book/ru/metadata/toc.json

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@
327327
"Обобщения в TypeScript",
328328
"Параметры типа - extends (generic constraints)",
329329
"Параметра типа - значение по умолчанию = (generic parameter defaults)",
330-
"Параметры типа - как тип данных"
330+
"Параметры типа - как тип данных",
331+
"Модификаторы вариантности параметров типа in и out"
331332
]
332333
},
333334
{
@@ -344,7 +345,8 @@
344345
"Предыстория возникновения import type и export type",
345346
"import type и export type - форма объявления",
346347
"Импорт и экспорт только типа на практике",
347-
"Вспомогательный флаг --importsNotUsedAsValues"
348+
"Вспомогательный флаг --importsNotUsedAsValues",
349+
"Разрешение импорта и экспорта только типа с помощью resolution-mode"
348350
]
349351
},
350352
{
@@ -437,7 +439,8 @@
437439
"subtitles": [
438440
"Условные типы на практике",
439441
"Распределительные условные типы (Distributive Conditional Types)",
440-
"Вывод типов в условном типе"
442+
"Вывод типов в условном типе",
443+
"Ограничение infer с помощью extends"
441444
]
442445
},
443446
{
@@ -700,7 +703,8 @@
700703
"noImplicitOverride",
701704
"useUnknownInCatchVariables",
702705
"exactOptionalPropertyTypes",
703-
"preserveValueImports"
706+
"preserveValueImports",
707+
"moduleSuffixes"
704708
]
705709
}
706710
]

0 commit comments

Comments
 (0)