Type Queries (запросы типа), Alias (псевдонимы типа)¶
Как сначала определить сложное значение, а затем одной строкой описать его тип? Или как конкретизировать более общий идентификатор типа и тем самым увеличить семантическую привлекательность кода? На два этих важных вопроса и поможет ответить текущая глава.
Запросы Типа¶
Механизм запроса типа (Type Queries) позволяет получить тип, связанный со значением по его идентификатору и в дальнейшим использовать его как обычный тип. Запрос типа осуществляется оператором typeof
, после которого идет идентификатор, ссылающийся на значение. Запрос типа также может располагаться в местах указания типа.
1 2 |
|
С помощью данного механизма можно получить тип любой конструкции, будь то переменная, параметр функции или метода, а также член объекта и класса.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Запрос типа может быть очень полезен сторонникам минимализма, достигаемого при помощи вывода типов. К слову, я один из них. Тем, кто придерживается консерватизма, возможно, придется по душе идея ускорять написание тестов за счет механизма вывода типов. Ведь в тех ситуациях, когда для тестирования требуются не определенные в приложении типы данных, часто не хочется тратить время на их декларацию, но при этом хочется использовать автодополнение. Например, при тестировании метода класса может понадобиться тип, представляющий только его, но, поскольку для проекта подобный тип просто бессмыслен, его придется определять в контексте самих тестов, что гораздо проще сделать при помощи механизма запроса типа. Все это вместе в TypeScript становится возможным благодаря выводу типов в паре с оператором запроса типа.
Представьте значение, присвоенное переменной, тип которой не указан явно. Теперь представьте, что это значение нужно передать в функцию, параметр которой также не имеет явного указания типа. В этом случае в функции будет сложно работать с параметрами, так как вывод типов определит его принадлежность к типу any
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
Не стоит даже рассуждать, оставить так или указать типы, которые, возможно, предварительно нужно ещё задекларировать. Вместо этого нужно прибегнуть к механизму запроса типа. Запрос типа позволяет одновременно решить две задачи, одна из которых связана с проблемами, сопутствующими типу any
, а другая — минимализму и расходу времени на декларирование типов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Псевдонимы Типов¶
Создание псевдонимов типа (types alias) — ещё одна из множества возможностей TypeScript, которые невозможно переоценить. Псевдоним типа объявляется при помощи ключевого слова type
, после которого следует идентификатор (имя) псевдонима, а за ним идет оператор присваивания =
, справа от которого находится тип, ассоциирующийся с псевдонимом.
1 |
|
Объявляться псевдоним типа может в контексте модулей, функций и методов.
1 2 3 4 5 6 7 8 9 10 11 |
|
Так как псевдонимы типов являются лишь псевдонимами для реальных типов, они не оставляют следа в коде после компиляции, к тому же их нельзя было расширять (extends
) и реализовать (implements
) в ранних версиях языка (до 2.7). Сейчас псевдоним типа можно реализовать или расширить, только если он представляет объектный тип (object type
) или пересечение объектных типов со статически известными членами. Кроме того, псевдонимы типов нельзя использовать в таких операциях типами времени выполнения как typeof
и instanceof
. Если псевдоним типа будет создан для объекта, то при попытке создать его экземпляр возникнет ошибка.
1 2 3 4 5 6 7 8 9 |
|
Псевдонимы типов можно создавать как для типов объединений, так и для типов пересечений.
1 2 |
|
Давно доказано, что идентификаторы типов, которые однозначно говорят о своем предназначении, облегчают понимание кода и его поддержку и, тем самым, сокращают затраты на его написание. По этой причине имена типов могут получаться очень длинными. Создание объединений или пересечений из нескольких типов с длинными именами может привести к ситуации, при которой код не поместится на одной строчке, что приведет к обратному эффекту, то есть затруднит его чтение.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
При работе с типами объединения и пересечения, псевдонимы типов позволяют повысить читаемость кода за счет сокрытия множества типов за одним компактным идентификатором.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Псевдонимы типов можно выносить в отдельные модули, а затем импортировать их в места назначения. Если модуль, содержащий псевдонимы типов, содержит только их, современные сборщики не будут включать такой модуль в сборку. Другими словами, модуль растворится точно так же, как и другие, не имеющие место в JavaScript, конструкции TypeScript.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Как было сказано ранее в секции Псевдонимы Типов, в тех редких случаях, когда декларированием типов, требующихся только для тестирования, можно пренебречь, механизм запроса типов помогает получить тип для указания в аннотации типа прямо из значения. Это дает все возможности типизации, за исключением читаемости кода, поскольку выражение запроса не персонализирует полученный тип. Хотя в примере, иллюстрирующем работу механизма запроса типа, константа STANDART_NORMAL
имеет вполне говорящий идентификатор, допускаются случаи, при которых подобного будет сложно добиться. При худшем сценарии идентификатор может иметь общий смысл.
1 2 3 4 5 |
|
В таких случаях псевдоним типа может оказать неоценимую помощь. Ведь экономия времени, затраченного на декларирование типов, не лишит код его выразительности и семантики.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Есть ещё пара особенностей псевдонимов, указание которых в данной главе было бы преждевременным, поэтому здесь о них будет лишь упомянуто. Во-первых, вынести объявления кортежа (Tuple
), речь о котором пойдет далее в главе Object, Array, Tuple, можно только в описание псевдонима. Во-вторых, создать такие типы сопоставления, как, например, Readonly
, Partial
, Pick
, Record
и им подобные, можно исключительно на основе псевдонимов типов. Перечисленные типы будут подробно рассмотрены в главе Readonly, Partial, Required, Pick, Record.