Как стать автором
Обновить

Комментарии 28

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

Спасибо за публикацию! Как раз начал облагораживать legacy код на JS, планирую перевести всю кодовую базу на TS — эта функция поможет подготовить старый код к портированию.
НЛО прилетело и опубликовало эту надпись здесь

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

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

Баги, которые реально встречаются в коде без указания типов — это когда в функцию, принимающую аргумент типа 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. Быть сторонником тестов и при этом слепо доверять приходящим извне данным — это мощно!
НЛО прилетело и опубликовало эту надпись здесь
> Что проще 2 == '2' или 2 === Number('2')?

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

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

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

Ну и не надо забывать, что стоимость использования тс — нулевая. А если можно бесплатно получить некоторый бонус, то какой смысл от него отказываться, каким бы маленьким он ни был?
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
> Почему вы всё время забываете про тесты? Вы их никогда не писали что-ли?

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

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

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

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

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

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

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

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

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

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

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

Это уж не говоря о том, что любой рефакторинг без типов превращается в ад (а в вебе рефакторинг происходит постоянно).
НЛО прилетело и опубликовало эту надпись здесь
> Это фича 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).

И да, я до сих пор не понимаю как форсировать контракты в большой команде разработчиков на динамическом языке. В каждой функции проверять, передали ли туда данные нужного типа и бросать исключение?
НЛО прилетело и опубликовало эту надпись здесь

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

НЛО прилетело и опубликовало эту надпись здесь

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.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории