Pull to refresh

Comments 28

Почему-то в WebStorm у меня эта история с @ts-check не завелась: TypeScript не ругается и IDE не подчеркивает. Хотя если просто описать интерфейсы в отдельном .ts и прописывать типы в js-doc, то интеллисенс здорово умнеет.

Спасибо за публикацию! Как раз начал облагораживать legacy код на JS, планирую перевести всю кодовую базу на TS — эта функция поможет подготовить старый код к портированию.
UFO just landed and posted this here

Вопрос в размере кодовой базы. Если всё входит в одну среднюю голову одного среднего программиста — то проблем нет. Проблемы начинаются тогда, когда проект растёт.

Typescript для веб-разработчика — это как каска на стройке. Если рабочий отказывается ее носить, потому что «ее надевать долго» или «это у всяких дураков кирпичи на голову падают», его сложно воспринимать всерьез.
UFO just landed and posted this here
Статическая строгая типизация не заменяет тесты, однако она позволяет существенно сократить их количество. Кроме того, она частично заменяет документацию, существенно упрощает и повышает качество подсказок в IDE, рефакторинга и оптимизаций. Отказываться от этих преимуществ есть смысл только в том случае, если весь исходный код программы влезает на один экран.

Баги, которые реально встречаются в коде без указания типов — это когда в функцию, принимающую аргумент типа A, передают значение типа B. Повсеместный пример в JS — сторонняя библиотека, принимающая при инициализации объект-конфиг. Как быть уверенным, что в каком-нибудь свойстве не закралась опечатка? Что не передал строку, когда нужно было массив с одной строкой? Каждый раз сверяться с документацией на сайте, если она вообще есть?

Если претит сама идея писать на каком-то новом транслируемом языке, то можно использовать Flow и описывать типы в комментариях. Код остается чистым Javascript'ом, однако все равно проверяется статически. Проверки у Flow слегка получше, а тулинг слегка похуже, поэтому выбор между ними — сугубо дело вкуса.

Вот пример вполне реального бага, который возник из-за нестрогой типизации:
if(this.flag) {
    this.doStuff();
}

Оказалось, что flag объявили не как свойство, а как метод (забыли модификатор get). Условие срабатывало всегда, потому что функция неявно приводилась к виду truthy. Любопытно, что в этом случае даже Typescript не спас — такое неявное приведение в нем допустимо, вероятно ради совместимости с идиомами в Javascript. Надеюсь, в будущих версиях позволят это запрещать специальным флагом компилятора.

С удовольствием послушаю историю про то, как наличие строгой типизации вызвало баг!
UFO just landed and posted this here
JSDoc — стандарт де факто — делает то же самое.
JSDoc + Flow тоже хороший вариант. А вот если использовать только один JSDoc, то все проверки оказываются на честном слове.

Только что говорили о тестах, уже забыли?
Сколько кода потребуется написать, чтобы выявить ошибку в этой строчке?
$('.dropdown').selectize({ max_items: 3 });
Вместо этого можно одной командой установить @types/selectize и компилятор сразу же скажет — свойство должно называться maxItems. По сути, это те же тесты, только их за вас уже написали авторы библиотеки или участники сообщества.

перестало работать сравнение вида 2 == '2'
Это же контрпример :) Бага в вашем случае была в том, что сервер присылал строку вместо числа, а строгая проверка позволила ее выявить и исправить.
UFO just landed and posted this here
Да всё держится на честном слове, если так рассуждать.
Отнюдь. Если ошибка в TS, она поймается на этапе сборки, а в JS — только при запуске. Понимаете разницу?

Сваливать ошибки на других
Окей, возможно ошибка все-таки у вас — вы решили, что сервер должен присылать числа, когда он присылает строки.

Javascript же умеет преобразовывать типы, и ответить вам будет нечего
Есть целый сайт, посвященный ответу на вопрос «почему неявное приведение зло»: WTF JS. Если собеседник настаивает на обратном, пусть объяснит пару примеров.

Поменяет сервис протокол — и что, всё переписывать что-ли? Или будете утверждать, что это фича?
Вот пример: вы получаете от API стоимость товара, прибавляете наценку и списываете деньги с пользователя. Вдруг сервис прислал строку вместо числа — и вместо 10 + 2 = 12 вы списали '10' + 2 = '102' рубля.

Невозможность такой ситуации — это ключевая фича. Она называется Fail-fast. Быть сторонником тестов и при этом слепо доверять приходящим извне данным — это мощно!
UFO just landed and posted this here
> Что проще 2 == '2' или 2 === Number('2')?

Второй вариант проще, конечно же. Вы же эту очевидность имели в виду?

> Вы смотрите на частности и за деревьями не видите леса. Тесты и прочее уменьшают это число на 20–80% (в зависимости от организации процесса). TS от силы на 1%, вот и вся разница.

Типизация нужна не для того, чтобы ловить ошибки, а чтобы ловить их _рано_. Чем раньше обнаружена ошибка — тем быстрее ее можно исправить. В случае с типизацией огромное количество ошибок исправляется просто мгновенно — за счет рабочего автокомплита, например. Если на исправление ошибки с тестами вы тратите условные 5-10сек, а с тс — 0сек, то тысяча-другая таких ошибок уже экономит время порядка часов, а поскольку возникают такие ошибки практически в каждой строке (а часто — по несколько на строку), то вы поняли. И это не учитывается время на написание тестов.

Ну и не надо забывать, что стоимость использования тс — нулевая. А если можно бесплатно получить некоторый бонус, то какой смысл от него отказываться, каким бы маленьким он ни был?
UFO just landed and posted this here
UFO just landed and posted this here
> Почему вы всё время забываете про тесты? Вы их никогда не писали что-ли?

Еще раз, типизация для того, чтобы ловить ошибки _рано_. Да, тесты тоже ошибку поймают — но очень, очень поздно.

> Лол, что?! Только не надо прямого вранья! У вас мгновенная компиляция что-ли?

У меня тайпчек в ИДЕ. Да, де-факто мгновенный.

> Опять враньё. Вы тратите время на написание громоздких конструкций типов.

Нет, не трачу. Описания типов значительно более компактны, чем тот же jsdoc. При этом более выразительны. Так что на практике я _экономлю_ на том, что пишу типы вместо использования более громоздких форматов документации.

> У вас вендор-лок, в конце концов.

Apache license, какой еще вендор-лок?

> Вы тратите время на компиляцию.

Это было бы аргументом только в том случае, если бы и так не было всякого тулчейна вроде бабелов и вебпаков. Да и то — кого волнует секунда-две на компиляцию? Никого.

> Почему вы постоянно игнорируете сильные аргументы и держитесь за свои слабые, не подтверждённые, утверждения как за мамину ручку?

Наличие полноценного автокомплита, компактная документация, быстрое обнаружение ошибок — это вполне себе подтвержденные утверждения, в истинности которых может любой убедиться на практике.

Это уж не говоря о том, что любой рефакторинг без типов превращается в ад (а в вебе рефакторинг происходит постоянно).
UFO just landed and posted this here
> Это фича IDE, а не Typescript. IDE может так и без TS.

Нет, не может. Чтобы чекнуть язык, должна быть система типов.

> Опять выдумаете.

Нет, не выдумываю. Просто сравните два варианта описания на примере. Кроме того, типы всегда актуальны, в отличии от 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).

И да, я до сих пор не понимаю как форсировать контракты в большой команде разработчиков на динамическом языке. В каждой функции проверять, передали ли туда данные нужного типа и бросать исключение?
UFO just landed and posted this here

Крокфорд пользуется огромным авторитетом в сообществе, но я как вспомню его ненастраиваемый jslint c куцым набором правил, половина из которых — субъективная вкусовщина...

UFO just landed and posted this here

Good Parts мне понравилась больше, чем jslint, но тоже не целиком.

Можно чуть подробнее насчет использования файлов d.ts с обычным js кодом?
Ура, переизобрели closure compiler который уже лет 10 умеет это делать. Жалко, конечно что closure так и не взлетел. Он и статическую типизацию поддерживает и по степени обфускации будет на шаг вперед всех остальных текущих библиотек. К сожаление отсутствует хорошая интеграция с npm и остальными популярными тулами.

Не взлетел, потому что барахло по объективным причинам. Тайп-чекинг, ЕМНИП, там очень выборочный; с IDE не интегрируется; аннотации не совместимы с js-doc; сжатие… ну когда-то лидировал, сейчас примерно на равных с uglify. Плюс они ухитрились сделать неудобный cli.

> Ура, переизобрели closure compiler который уже лет 10 умеет это делать. Жалко, конечно что closure так и не взлетел.

В closure compiler очень слабая система типов, по назначению это оптимизатор-обфускатор. В качестве тайпчекера js на практике он применяться не может (разве что в ряде оооочень сильно ограниченных кейсов). В общем-то тут ничего странного и нет — когда писали closure compiler, то нормально типизировать динамические языки еще не умели, это результат научных работ последних лет 3-4.
Sign up to leave a comment.

Articles