Комментарии 28
Почему-то в WebStorm у меня эта история с @ts-check не завелась: TypeScript не ругается и IDE не подчеркивает. Хотя если просто описать интерфейсы в отдельном .ts и прописывать типы в js-doc, то интеллисенс здорово умнеет.
Вопрос в размере кодовой базы. Если всё входит в одну среднюю голову одного среднего программиста — то проблем нет. Проблемы начинаются тогда, когда проект растёт.
Баги, которые реально встречаются в коде без указания типов — это когда в функцию, принимающую аргумент типа A, передают значение типа B. Повсеместный пример в JS — сторонняя библиотека, принимающая при инициализации объект-конфиг. Как быть уверенным, что в каком-нибудь свойстве не закралась опечатка? Что не передал строку, когда нужно было массив с одной строкой? Каждый раз сверяться с документацией на сайте, если она вообще есть?
Если претит сама идея писать на каком-то новом транслируемом языке, то можно использовать Flow и описывать типы в комментариях. Код остается чистым Javascript'ом, однако все равно проверяется статически. Проверки у Flow слегка получше, а тулинг слегка похуже, поэтому выбор между ними — сугубо дело вкуса.
Вот пример вполне реального бага, который возник из-за нестрогой типизации:
if(this.flag) {
this.doStuff();
}
Оказалось, что
flag
объявили не как свойство, а как метод (забыли модификатор get
). Условие срабатывало всегда, потому что функция неявно приводилась к виду truthy. Любопытно, что в этом случае даже Typescript не спас — такое неявное приведение в нем допустимо, вероятно ради совместимости с идиомами в Javascript. Надеюсь, в будущих версиях позволят это запрещать специальным флагом компилятора.С удовольствием послушаю историю про то, как наличие строгой типизации вызвало баг!
JSDoc — стандарт де факто — делает то же самое.JSDoc + Flow тоже хороший вариант. А вот если использовать только один JSDoc, то все проверки оказываются на честном слове.
Только что говорили о тестах, уже забыли?Сколько кода потребуется написать, чтобы выявить ошибку в этой строчке?
$('.dropdown').selectize({ max_items: 3 });
Вместо этого можно одной командой установить @types/selectize
и компилятор сразу же скажет — свойство должно называться maxItems
. По сути, это те же тесты, только их за вас уже написали авторы библиотеки или участники сообщества.перестало работать сравнение вида 2 == '2'Это же контрпример :) Бага в вашем случае была в том, что сервер присылал строку вместо числа, а строгая проверка позволила ее выявить и исправить.
Да всё держится на честном слове, если так рассуждать.Отнюдь. Если ошибка в TS, она поймается на этапе сборки, а в JS — только при запуске. Понимаете разницу?
Сваливать ошибки на другихОкей, возможно ошибка все-таки у вас — вы решили, что сервер должен присылать числа, когда он присылает строки.
Javascript же умеет преобразовывать типы, и ответить вам будет нечегоЕсть целый сайт, посвященный ответу на вопрос «почему неявное приведение зло»: WTF JS. Если собеседник настаивает на обратном, пусть объяснит пару примеров.
Поменяет сервис протокол — и что, всё переписывать что-ли? Или будете утверждать, что это фича?Вот пример: вы получаете от API стоимость товара, прибавляете наценку и списываете деньги с пользователя. Вдруг сервис прислал строку вместо числа — и вместо
10 + 2 = 12
вы списали '10' + 2 = '102'
рубля.Невозможность такой ситуации — это ключевая фича. Она называется Fail-fast. Быть сторонником тестов и при этом слепо доверять приходящим извне данным — это мощно!
Второй вариант проще, конечно же. Вы же эту очевидность имели в виду?
> Вы смотрите на частности и за деревьями не видите леса. Тесты и прочее уменьшают это число на 20–80% (в зависимости от организации процесса). TS от силы на 1%, вот и вся разница.
Типизация нужна не для того, чтобы ловить ошибки, а чтобы ловить их _рано_. Чем раньше обнаружена ошибка — тем быстрее ее можно исправить. В случае с типизацией огромное количество ошибок исправляется просто мгновенно — за счет рабочего автокомплита, например. Если на исправление ошибки с тестами вы тратите условные 5-10сек, а с тс — 0сек, то тысяча-другая таких ошибок уже экономит время порядка часов, а поскольку возникают такие ошибки практически в каждой строке (а часто — по несколько на строку), то вы поняли. И это не учитывается время на написание тестов.
Ну и не надо забывать, что стоимость использования тс — нулевая. А если можно бесплатно получить некоторый бонус, то какой смысл от него отказываться, каким бы маленьким он ни был?
Еще раз, типизация для того, чтобы ловить ошибки _рано_. Да, тесты тоже ошибку поймают — но очень, очень поздно.
> Лол, что?! Только не надо прямого вранья! У вас мгновенная компиляция что-ли?
У меня тайпчек в ИДЕ. Да, де-факто мгновенный.
> Опять враньё. Вы тратите время на написание громоздких конструкций типов.
Нет, не трачу. Описания типов значительно более компактны, чем тот же jsdoc. При этом более выразительны. Так что на практике я _экономлю_ на том, что пишу типы вместо использования более громоздких форматов документации.
> У вас вендор-лок, в конце концов.
Apache license, какой еще вендор-лок?
> Вы тратите время на компиляцию.
Это было бы аргументом только в том случае, если бы и так не было всякого тулчейна вроде бабелов и вебпаков. Да и то — кого волнует секунда-две на компиляцию? Никого.
> Почему вы постоянно игнорируете сильные аргументы и держитесь за свои слабые, не подтверждённые, утверждения как за мамину ручку?
Наличие полноценного автокомплита, компактная документация, быстрое обнаружение ошибок — это вполне себе подтвержденные утверждения, в истинности которых может любой убедиться на практике.
Это уж не говоря о том, что любой рефакторинг без типов превращается в ад (а в вебе рефакторинг происходит постоянно).
Нет, не может. Чтобы чекнуть язык, должна быть система типов.
> Опять выдумаете.
Нет, не выдумываю. Просто сравните два варианта описания на примере. Кроме того, типы всегда актуальны, в отличии от jsdoc.
> Тулчейн опционален, вы вообще можете написать и разрабатывать прямо в браузере со всеми модулями, ES2016+ и красивыми тестировщицами
Чисто теоретически — могу, но практически — нет, не могу.
> Если бы всё так было просто и быстро, но вы ещё добавляете лишнее время компиляции.
Так тем более. Если было 0 сек. компиляции, а стало секунда-две — это и так не влияет ни на что существенно. А если было 20 сек, а стало 21-22 — то тем более плевать.
> 1. Опять путаете фичи IDE.
Эти фичи ИДЕ невозможны без типизации. Отказываетесь от типизации — отказываетесь от фич.
> Синдром утёнка.
Нет, это факт. Например, вы поменяли поля в некотором объекте, как без типов определить все места использования объекта и поправить обращения?
> 2. Вы не привели ссылок на академические исследования.
Исследования чего? Проверку какого именно тезиса вы хотите увидеть?
Я с вами спорить не буду, но все-таки свои пять копеек вставлю, вдруг кто-то прочтет и задумается.
Я вот тоже примерно так раньше рассуждал — сдалась мне ваша типизация, [] == false
, лол, «белки истерички.jpg». Очевидно, явная типизация от багов в логике не спасает, против этого только тесты. Зато она спасает от лишней нагрузки мою голову, которую я могу приложить на написание ну хоть тех же тестов.
Все дело в том, что явная типизация — это как документация, в которую не надо лезть. Перепутал порядок аргументов? опечатался в названии метода? Не помнишь, принимает либа число или строку, массив или словарь? Вернул не то значение из функции? Все это видно сразу прямо в IDE, без выпадения из потока на время запуска тестов и сборку фронтендом.
Еще раз: явная типизация не спасает от багов в бизнес-логике, она спасает от дурацких ошибок. Ну и тупо упрощает набор кода, чего уж греха таить. Меньше отрывов — меньше выпадений из продуктивного состояния.
Теперь что касательно js-doc. Это бы работало, если бы это был синтаксически зафиксированный стандарт. На деле кому-то пофиг, кто-то не в курсе, что IDE понимает jsdoc, кто-то упарывается каким-то кривым docco или еще какой дрянью, кто-то пишет под closure compiler и у них своя атмосфэра, кто-то пишет в VS, которая всего года три назад понимала только свой формат комментов, а комменты все стерпят, вот и пишут кто во что горазд, а потом интеллисенс не работает. Явная типизация берет на себя роль зафиксированного, понимаемого всеми сторонами синтаксиса документации.
Во-первых, я думаю вы понимаете, что если у вас есть JSDoc и тесты, то статическая типизация у вас УЖЕ есть, только неявно и контроллируется она вручную. То, что вы умеете и можете это делать средставами, удобными именно вам, не значит что ваше решение объективно лучшее.
Во-вторых, ошибки на этапе компиляции — это, пожалуй, объективно полезно. Да, вы можете сказать, что тесты вы запускаете также в процессе сборки проекта и можно сказать что это эквивалентное средство. Но если я могу достичь аналогичного результата с помощью информации, которая обрабатывается И компиляторо И программистом одинаково (синтаксис строго-типизированного языка), зачем мне эту информацию разделять между документацией для разоработчика (JSDoc) и тестами?
В третьих, я думаю тесты — это замечательная вещь, которой можно и нужно покрыть всё, что НЕ УДАЛОСЬ покрыть более продвинутыми проверками, такими как типизация (и прочие виды проверок в compile-time). Иными словами, я считаю мы должны идти от тестов к более специализированным и строгим средствам верификации, а не наоборот.
Давать программисту сначала свободу в виде динамической типизации всех переменных и значений, а потом в большинстве случаев эту свободу «забирать», ограничивая тестами РЕАЛЬНЫЕ ветви исполнения кода и РЕАЛЬНЫЕ типы данных, которые код может обработать — это неэффективно. А в реальном коде именно так и будет происходить — не так уже часто нужен действительно «полностью динамический» тип (top-type или any).
И да, я до сих пор не понимаю как форсировать контракты в большой команде разработчиков на динамическом языке. В каждой функции проверять, передали ли туда данные нужного типа и бросать исключение?
Крокфорд пользуется огромным авторитетом в сообществе, но я как вспомню его ненастраиваемый jslint c куцым набором правил, половина из которых — субъективная вкусовщина...
Не взлетел, потому что барахло по объективным причинам. Тайп-чекинг, ЕМНИП, там очень выборочный; с IDE не интегрируется; аннотации не совместимы с js-doc; сжатие… ну когда-то лидировал, сейчас примерно на равных с uglify. Плюс они ухитрились сделать неудобный cli.
В closure compiler очень слабая система типов, по назначению это оптимизатор-обфускатор. В качестве тайпчекера js на практике он применяться не может (разве что в ряде оооочень сильно ограниченных кейсов). В общем-то тут ничего странного и нет — когда писали closure compiler, то нормально типизировать динамические языки еще не умели, это результат научных работ последних лет 3-4.
Использование преимуществ TypeScript в JavaScript разработке