Вчера большинство проголосовало за сравнение статических систем типов, поэтому поехали
👇👇👇
К моему сожалению, мне попадалось много молодых разработчиков, кто считает что эти два пункта взаимозаменяемые
- статическая типизация
- typescript
Тайпскрипт это здорово, он полезен и можно научиться любить его и работать с ним. Но не стоит думать что это панацея
Для начала про типы в целом, там где они не влияют на рантайм и вырезаются при сборки, алгоритм их использования должен быть примерно такой
Не доверяем всем данным из вне, будь то ввод пользователя, ответ бекенда и другие. Эти данные нужно валидировать.
Далее идёт зелёная часть в которой мы можем безопасно* работать с нашими данными
На изображении видно как жёлтый немного просачивается в зелёную зону, в системах типов есть баги, про них нужно знать. Такое бывает, жизнь случается ¯_(ツ)_/¯
Мне бы хотелось устроить большое сравнение и втащить сюда sound elm, purescript с его коммюнити академических фетишистов, reason или bucklescript или rescript, ладно сдаюсь, поэтому сегодня будет только flow и typescript
Если совсем зажмурится, то может показаться что это очень похожие инструменты, но это не так и в этом треде попробуем разобраться почему
Цель flow - быть sound type system. Если флоу говорит не ругается, то TypeError не может случится. Это так же означает что возможны false positive, то есть флоу может ругаться на те места где по бизнесс логике ошибки не может случится
Цель TS - быть complete type system. Другими словами команда тайпскрипта пытается найти баланс между достижением type safety и продуктивной работы разработчика. Это 3ий пункт в их публичных не целях.
github.com/Microsoft/Type…
Это значит что всё что TS помечает ошибкой, действительно ошибка, но могут быть false negative - намеренно пропущенные потенциальные ошибки
Жду дня, когда буду находиться на встрече по разбору инцидентов из прода
- Антон, почему у нас тогда прод сломался Мы потеряли миллионы
- Просто мне было удобно писать на TS 🤗
Дальше про отличия:
Flow - только аннотации типов, которые никак не влияют на рантайм
TS - отдельный язык, который помимо типов так же добавляет свои runtime конструкции вроде enums, decorators, parameter properties etc
Тут же нужно отметить что typescript состоит из 2ух инструментов
- тайпчекер для проверки типов
- компилятор который превращает код из ts в js
Далее можно кучу всего написать про отдельные отличия как flow с номинальной+струтурной vs только структурной типизацией у ts, наличие const assertions и прочие, но это скорее всего будет не интересно. Поэтому следующая пачка будет про вещи на которых можно больно спотыкаться😩
Флоу позволяет спредить типы объектов для того что бы мержить их между собой, пайпы используются для обозначения строгих объектов, интерсекшенами (&) мы почти не пользовались
В TS нет спредов, но поэтому давайте интерсектить, но можно доинстрсектится и получить never, потому что нет сегодня значения удовлетворяющего string & boolean, во флоу проблема будет похожа
Если хотим узнавать об ошибках коллизии ключей при написании, то начинаем смотреть в сторону интерфейсов вместо тайп алиасов
Если же нам нужен аналог мержа, то пишем небольшой утил
Для undefined во флоу есть void, в тс есть два типа void и undefined. Между ними есть отличия
void для определения чегото чем не нужно пользоваться
undefined - валидное значение
This
Флоу пытается самостоятельно вывести тип this в зависимости от контекста, а в ts вы можете явно его указать назвав первый аргумент функции this. Надеюсь что это нигде и никому никогда не понадобится, кроме серверного кода яндекс маркета😅
Про any vs unknown / mixed расписывать не буду
Видите any? Удаляйте, ставте mixed(flow)/unknown(ts) - нервы дороже, пишите явные проверки
Стоит отметить что документация у этих инструментов очень хороша
typescript - читаешь и можнешь просто писать на этом языке
flow - прочитал как книжку и +200 к iq, понимаешь про устройство систем типов, вариативность типов, но как flow пользоваться нужно еще разобраться
Сужение типов aka type refinement aka type narrowing
Не вижу смысла дублировать документацию, поэтому если вам не очевидно почему на картинке в первом условии тип не сужается, а во стором сужается, то вот две ссылки
flow.org/en/docs/lang/r…
typescriptlang.org/docs/handbook/…
Если бы мне давали 1$ за каждый раз когда у меня спрашивают почему оно так
Далее type guards / type predicates
Писать проверки прямо в условиях не удобно и хочется их переиспользовать, это умеют оба языка. Вот флоу
А вот тайпскрипт, обращаем внимание что синтаксис нам позволяет явно указать что мы проврям что аргумент это строка
С гардами нужно быть аккуратным, ведь случайно можно написать не ту проверку и тогда флоу перестанет сужать тип
В случае с тайпскриптом ему всё равно что вы там проверяете и типы будут продолжать сужаться, поэтому считаю это настоящим револьвером для отстреливания нижних конечностей
Если можете заинлайнить проверку в условие - такбудет безопасней ✅
В ts еще есть assert type guard'ы, удобная штука, если вам нужно заассертить какое то значение, но она наследует все те же проблемы обычных гардов, имейте введу
уф, а про саппрешены ведь не написал, можно игнорировать ошибки, все саппрешн комментарии($FlowFixMe) во флоу будут помечаться как ворнинги или с флагом в конфиге ошибками и вы в любом случае узнаете о том что есть неиспользуемые сапрешены, которые не игнорируют ни-че-го
Долгое время в ts был только @ts-ignore и это было недуобно, потому что можно после ухода ошибки он оставался висеть, а если всплывала новыая ошибка, то он её гасил. Как пользователь из редактора вы не могли об этом узнать и узнавали об этом из поломанного прода.
В 3.9 появился [@ts](https://twitter.com/ts)-expect-error который сообщит вам если он является лишним, предлагаю всключить estlint правило и запретить [@ts](https://twitter.com/ts)-ignore в принципе
github.com/typescript-esl…
Еще одна опасная* фича TS это null assertions, когда у вас есть nullable значение, но вы знаете лучше компилятора что там не null и просите его проигнорировать ваше отсутствие проверки. Имхо лучше эту фичу запретить линтером, вот и правило
github.com/typescript-esl…
Еще немного поною про тайпскрипт и пойдут его плюсы
Используй тайпскрипт говорили они, там строгие объекты говорили они
Туда же и массивы
Из остального ts нытья:
- отсутствие opaque типов
- если у вас дженерик функция, вы не можете передать один из ниескольких джинериков, если начали предавать, то передавайте всё остальные тоже
и еще чуть чуть
- дженерики с условиями 👉 <T extends Foo> ts относится T теперь ковариант, должен быть как Foo, но может содержать его расширять
- отсутствие инвалидации сужения типов
- отсутвие $Call, есть ReturnType и infer, но блин не то🙂
Как можно догадаться мне было сложно перейти на ts, но в какой то момент я понял что мои интересы расходятся с интересами команды тайпскрипта и это ок. Это нужно принять и жить с этим ¯_(ツ)_/¯
Дальше про плюсы TS
Жирнейший плюс это распространенность, почти на всё уже есть тайпинги если не в самой бибилотеке то в DefinitelyTyped
У TS есть поддержка JSDoc, не только как для описания типов, но и как документация к типам/функциям и тд, оно прорастает в хинты в редакторах 🤗
Наличие шаблонных строковых типов позволяет творить интересные вещи, например парсить джейсон не запуская джаваскрипт (ради бога не используйте это, фича крутая, библотека для пример)
github.com/jamiebuilds/js…
Если у вас redux, но не redux-toolkit, то может понравиться вот это
github.com/antonk52/rainb…
в целом "интегрированность" в современные инструменты у TS на высоте, это всегда было слабой чертой flow
В целом на этом можно сворачивать тему человека с мечтами о soundness, но пишущего на javascript
Забыл про что то? Вы хотели ухлышать про Х, но этого не было? Что пропустил?
Забыл интересные факты, например тайпскрипт не следует семверу
github.com/microsoft/Type…
github.com/microsoft/Type…