Здравствуйте, меня зовут Дмитрий Карловский и недавно я, вместе с Артуром Мукминовым, проводил воркшоп, где показывал как разрабатывать сложные типофункции через тестирование. Это 2 часа сурового программирования на типах. Так что в качестве тизера, ловите разбор курьёзов тайпскриптовой системы типов.
Отношения - это сложно
Проверить является ли один тип подтипом другого очень просто, используя типотернарник:
type IsAExtendsB = A extends B ? true : false
На воркшопе мы разработали типофункцию Classify, принимающую 2 типа и возвращающую одно из 4 возможных значений:
[ A, '<:', B ] - A является строгим подтипом B.
[ A, ':>', B ] - B является строгим подтипом A.
[ A, '==', B ] - Оба типа являются подтипами друг друга (но не обязательно являются одинаковыми типами).
[ A, '!=', B ] - Ни один тип не является подтипом другого.
Кроме того, мы запилили типофункции Equal и Assert, позволяющие сравнивать типы на равенство, независимо от того, считает ли компилятор два разных типа подтипами друг друга или нет. Assert при этом ещё и валит проверку типов, если типы вдруг не совпали.
Всё есть объекты! Но это не точно..
Ну и первый же прикол - Object и object - это определённо разные типы, ибо примитивные типы являются подтипами первого, но не второго:
То есть отношение подтипизации в тайпскрипте не является транзитивным: если один тип (например, boolean) является подтипом другого (например, Object), а другой - третьего (например, object), то первый вовсе не обязательно является подтипом третьего - это надо проверять отдельно.
На диаграмме, все объектные типы раскрашены в голубой цвет. Они являются подтипами как Object, так и object.
Разные типы перечислений типов
Раз уж мы заговорили про булевый тип, то нельзя не упомянуть, что он - ничто иное, как кроткий алиас для объединения пары литеральных типов:
type boolean_is_true_or_false = Assert<
boolean,
true | false
>
С числовыми перечислениями всё в принципе аналогично:
https://page.hyoo.ru/#!=lj5tx3_678izw
Здравствуйте, меня зовут Дмитрий Карловский и недавно я, вместе с Артуром Мукминовым, проводил воркшоп, где показывал как разрабатывать сложные типофункции через тестирование. Это 2 часа сурового программирования на типах. Так что в качестве тизера, ловите разбор курьёзов тайпскриптовой системы типов.
Отношения - это сложно
Проверить является ли один тип подтипом другого очень просто, используя типотернарник:
На воркшопе мы разработали типофункцию Classify, принимающую 2 типа и возвращающую одно из 4 возможных значений:
[ A, '<:', B ]
- A является строгим подтипом B.[ A, ':>', B ]
- B является строгим подтипом A.[ A, '==', B ]
- Оба типа являются подтипами друг друга (но не обязательно являются одинаковыми типами).[ A, '!=', B ]
- Ни один тип не является подтипом другого.Кроме того, мы запилили типофункции Equal и Assert, позволяющие сравнивать типы на равенство, независимо от того, считает ли компилятор два разных типа подтипами друг друга или нет. Assert при этом ещё и валит проверку типов, если типы вдруг не совпали.
Всё есть объекты! Но это не точно..
Ну и первый же прикол -
Object
иobject
- это определённо разные типы, ибо примитивные типы являются подтипами первого, но не второго:Однако, если мы сравним их, то выяснится, что они являются подтипами друг друга:
То есть отношение подтипизации в тайпскрипте не является транзитивным: если один тип (например,
boolean
) является подтипом другого (например,Object
), а другой - третьего (например,object
), то первый вовсе не обязательно является подтипом третьего - это надо проверять отдельно.На диаграмме, все объектные типы раскрашены в голубой цвет. Они являются подтипами как
Object
, так иobject
.Разные типы перечислений типов
Раз уж мы заговорили про булевый тип, то нельзя не упомянуть, что он - ничто иное, как кроткий алиас для объединения пары литеральных типов:
С числовыми перечислениями всё в принципе аналогично:
И состоят они вроде бы из чисел (даже не литералов):
Но тут тайпскрипту внезапно сносит крышу:
Эй, тайпскрипт, ты куда первый тип потерял? Верни, где взял!
Вот, спасибо, совсем другое дело!
По всей видимости связано это с тем, что значения перечислений - это не простые литералы, а уникальные:
Ну да ладно, у нас ещё остались не разобранными строковые перечисления. Может показаться, что ведут они себя как и числовые, однако, внезапно:
Получается, что
number
является подтипом числового перечисления, а вотstring
подтипом строкового уже нет.Призраки прошлого
В Тайпскрипте есть пара специальных типов, которые находятся на противоположных концах иерархии:
never
представляет из себя пустое множество значений. То есть он является подтипом любого типа, и никакой другой тип не может быть его подтипом.unknown
же - это множество всех возможных значений. То есть это объединение вообще всех типов в один. Поэтому любой тип является подтипомunknown
.Но что это маячит рядом с ними? Да это же
any
! С одной стороны он полностью взаимозаменяем сunknown
:Но с другой же, он как кот Шрёдингера является подтипом
never
(и как следствие, любого другого типа доunknown
) и не является таковым одновременно:Короче,
any
пробивает дно во всех возможных смыслах. Тяжела участь тех, кто столкнётся с ним лицом к лицу...Весь код из статьи.
Счастливой отладки, ребята!