Итак, что же такое собственно TypeScript — наверно уже ни для кого не секрет. Но все же, хочу упомянуть, что это попытка Microsoft принести в JavaScript статическую типизацию. Примеры кода и задачи, которые он позволяет решать, можно посмотреть на официальном сайте или здесь на хабре, благо статей написано уже не мало. На хабре уже есть статья подобного рода TypeScript: общие впечатления, поэтому, чтобы не повторяться, я решил выделить плюсы и минусы работы с языком, опираясь на свой личный опыт. Вспомнить и перечислить плюсы и минусы языка оказалось довольно непросто.
Популярность языка
Проект TypeScript создан компанией Microsoft. Фактически его создателем является Аннерс Хейлсберг. Практически с самого начала TypeScript стал быстро набирать популярность в силу своей гибкости и производительности. Немало проектов, которые были написаны на JavaScript, стали переноситься на TypeScript. Рост интереса к этому языка вызван еще и тем, что ряд идей, которые в нем реализованы, в последующем стали частью нового стандарта JavaScript. Все больше проектов переписывается на этом языке, включая такие крупные как Angular 2.0 и vscode.
Цитаты авторитетных людей
TypeScript, возможно, один из лучших JavaScript языков на фронтенде. Код, который он генерирует, выглядит наиболее привлекательно. И я думаю, что он способен снять нагрузку со стандарта ECMAScript по реализации таких вещей, как декларации и классы. Андерс показал, что этот функционал хорошо поддерживается препроцессором, поэтому нет необходимости изменять основной язык.
Я считаю, что свободная типизация в JavaScript — это одно из достоинств языка и проверка типов переоценена. TypeScript добавляет удобства слишком дорогой ценой. И эта не та цена, за которую я готов платить.?
Дуглас Крокфорд — создатель JSLint. Оригинал
Для пользователей Visual Studio — TypeScript довольно хороший инструмент для разработки, и к тому же он отлично соответствует стандарту ES6. Я бы мог больше рассказать об этом языке, но не вижу смысла сравнивать его с Dart.
Брендан Айк — основатель JavaScript. Оригинал
Я огромный поклонник CoffeeScript хотя это и другой язык с самостоятельным синтаксисом. Что мне нравится в TypeScript — так это то, что статическая типизация позволяет обеспечить процесс компиляции с предупреждениями, умный рефакторинг кода. В дополнение к этому вы получаете легкую навигацию по коду. В текущей версии CoffeScript вы не получите таких возможностей.
Скотт Хансельман — евангелист Microsoft. Оригинал
Плюсы
О плюсах TypeScript написано довольно много. Поэтому постараемся тезисно отметить его преимущества:
- Поддержка многими популярными IDE:
- TypeScript — строго типизированный (опционально!) и компилируемый в JavaScript язык. Проще для освоения Java и C# программистами.
- TypeScript реализует многие концепции ООП, такие как наследование, полиморфизм, инкапсуляция и модификаторы доступа. В нем есть классы, интерфейсы и (даже!) абстрактные классы.
- Потенциал языка позволяет быстрее и проще писать сложные комплексные решения, которые легче развивать и тестировать в дальнейшем, чем на стандартном JavaScript.
- TypeScript — надмножество JavaScript, поэтому любой код на JavaScript будет выполнен и в TypeScript. Это, на мой взгляд, его главное преимущество перед конкурентами — например, Dart от компании Google, который является кардинально переработанным языком из Javascript. Есть статья по переводу проекта на Javascript в TypeScript
Минусы
Как мне кажется, что в большинстве случаев TypeScript хвалят. Поэтому мне хотелось написать свой пост о том, что же не так в Typescript. И как оказалось, найти минусы было довольно не просто.
- В процессе разработки имеем дело с файлами *.ts, *.d.ts, *.map, *.js. Слишком много дополнительных файлов, что бывает неудобно, если ваш проект небольшой.
- Не все браузеры поддерживают отладку TypeScript в консоли без лишних настроек.
- Множество нетривиальных классов. Чтобы писать код, опираясь на классы, приходится держать в голове какое свойство где находится. Например вместо одного класса Event существуют еще такие как MouseEvent, TouchEvent, KeyboardEvent и другие...
- Неявная статическая типизация. Всегда можно описать тип как any, что по факту отключит приведение к конкретному типу этой переменной.
- Это транспайлер, что подразумевает, что мы должны всегда иметь под рукой tsc
- d.ts декларации поддерживаются сообществом DefinitelyTyped и часто не соответствуют текущей версии библиотеки. Либо не учитывают сложных вариантов (generic-функции, возвращаемые значения нескольких типов)
Немного о статической типизации
В жизни каждого разработчика бывает время, когда он пишет код в свое удовольствие. Будь это домашний проект, или работа в команде над проектом, который только начали писать с нуля. Это один из прекрасных моментов, когда не приходится много думать о конфликтах в коде с коллегами и искать ошибки. Но проект растет, обрастает новым функционалом и багами, связанными в том числе и с типами, если вы пишете свой код на динамически типизированном языке, коим является JavaScript.
Какое может быть решение в этом случае? Писать тесты!
Но согласитесь, зачем проверять то, с чем чем хорошо может справиться машина еще на стадии компиляции? Языки со статической типизацией избавляют нас от излишнего написания дополнительных тестов, которые связаны с ошибками в типах. Поэтому TypeScript имеет большое преимущество перед JavaScript, если мы не игнорируем типы.
Рассмотрим простой пример
У нас есть функция, которая умеет складывает два числа:
function sum(a, b) {
return a + b;
}
Ваш заказчик предложил реализовать веб форму, в которой бы пользователь мог вводить складываемые числа:
var result = sum(
document.getElementById("input1").value,
document.getElementById("input2").value,
)
document.getElementById("result").innerText = result;
Пишем в наши поля ввода два числа, 2 и 3 и проверяем работу нашей функции:
23
Результат получился довольно неожиданный. Всё дело в том, что поле value у html-тега input возвращает результат типа «string» и JavaScript склеивает две строки «1» и «2» вместо того, чтобы сложить эти числа.
Пример, конечно довольно простой, но в реальной жизни ошибки могут быть и сложнее, и их бывает довольно трудно заметить на стадии разработки.
Решение подобной задачи довольно легко решается с помощью TypeScript:
function sum(a: number, b: number): number {
return a + b;
}
sum(2, 3); // Ok
sum(2, "3"); // Error!
Уже на этапе компиляции мы смогли обнаружить ошибку. Тратить силы лучше на разработку, а не на поиск ошибки и написания дополнительных тестов.
Вывод
Когда я думал над плюсами и минусами разработки на TypeScript, выделить минусы оказалось не просто. TypeScript больше оправдывает себя в крупных проектах. Это связано с тем, что разработка на нем занимает больше времени чем на JavaScript, из-за того что приходится помимо методов и классов описывать и их декларации. Но тем не менее, пока в JavaScript нет статической типизации, TypeScript является отличной альтернативой.
P.S. Целью моей статьи было разобраться в достоинствах и недостатках TypeScript и скорее всего я что-то упустил. Поэтому буду рад любым комментариям по существу.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (30)
forcewake
21.12.2015 15:39+3За это время мы привыкли друг к другу и пережили много успехов и разочарований.
А собственно где успехи, где разочарования?
Если пройтись по минусам, то тут тоже не всё так однозначно:
В процессе разработки имеем дело с файлами *.ts, *.d.ts, *.map, *.js. Слишком много дополнительных файлов, что бывает неудобно, если ваш проект небольшой.
Два последних известным всем тем, кто хоть немного сталкивался с front-end'ом. Первый, это собственно сам код (к слову, *.js -> *.ts ничего не сломает, но, думаю, вы об этом и так знаете)Не все браузеры поддерживают отладку TypeScript в консоли без лишних настроек.
Если высказали проблему, то может как-то расширить её — с чем столкнулись, как решали? Я, например, к сожалению, не сталкивался и было бы очень интересно прочитать про опыт других.Множество нетривиальных классов. Чтобы писать код, опираясь на классы, приходится держать в голове какое свойство где находится. Например вместо одного класса Event существуют еще такие как MouseEvent, TouchEvent, KeyboardEvent и другие...
Частично соглашусь, но с оговоркой, что вы только начали работать с языком. Впоследствии это как-то не замечается, возможно только у меня.Неявная статическая типизация. Всегда можно описать тип как any, что по факту отключит приведение к конкретному типу этой переменной.
Не соглашусь. Это скорее feature самого языка. Кроме того, проблему всегда можно решить. Можно, например, начать с этого.Это транспайлер, что подразумевает, что мы должны всегда иметь под рукой tsc
Если вспомнить, что мы работаем с языком, который нужно ещё компилировать — проблема как-то угасает. Дотнетчики не жалуются, что им нужен csc.exe :) Ну и не стоит забывать про то, что сейчас всё чаще и чаще всё собирается, компилируется с использованием grunt, gulp или webpackd.ts декларации поддерживаются сообществом DefinitelyTyped и часто не соответствуют текущей версии библиотеки. Либо не учитывают сложных вариантов (generic-функции, возвращаемые значения нескольких типов)
В этом и есть весь challenge — вы можете стать частью огромного сообщества, которое изменяет мир open source. Исправили/добавили что-то — в следующий раз кто-то поможет и вам.
Впрочем, комментарий и так слишком длинный.
Спасибо за статью — кто-то обязательно подчерпнёт для себя что-то новое и интересное.
Cyrus
21.12.2015 16:30+4Ощущение от TypeScript сменяется от энтузиазма относительно compile-time валидации кода до ощущения постоянной незавершенности. Ожидаешь некоторой жесткости в обмен на широкие возможности рефакторинга, но в текущих версиях инструментов их нет.
Отдельные эмоции от переписывания старого кода — в условиях нехватки времени подкупает возможность переименовать файлы и пользоваться обратной совместимостью. В команде это ведет к неподконтрольному росту использования any и как следствие улучшения качества конечного кода не наблюдается. Можно использовать флаг в tsconfig, запрещающий использование any, но гибкость тогда отпадает. Возможно в маленьком проекте и можно было бы переехать полностью, но заставлять описывать все интерфейсы — чрезчур жестоко для людей которые в разработке изначально с frontend.
Возможно это предвзятое мнение, сформированное ожиданием некоего браузерного C#, коим TypeScript конечно не является.
TheRabbitFlash
22.12.2015 00:11-8Хотите писать без головной боли — пишите на Haxe. TS в сравнении с Haxe — надувная баба. Причем проколотая, которую надо все время подкачивать. Почему баба? Потому, что идешь за удовольствием, а получаешь немного не то. Но пыжишься… пыжишься :D
TheRabbitFlash
22.12.2015 00:36-7это одно из достоинств языка и проверка типов переоценена.
Типы в контексте старого JS не нужны, да. Но в процессе разработки это ой как важно. Весьма приятно писать так:
var myArray : Array<MyClass>;
и при написании кода
myArray[i]. после точки начинать получать выпадающий списк с публичными методами из MyClass :)
Вот так работает Haxe, например.TheRabbitFlash
22.12.2015 12:57-4Минусуйте на здоровье :) С меня тоже ржали колхозники, когда я огород за 15 минут бабушке вспахал мотоблоком :) Причем ржали громче всех те, у кого максимально большие мозоли на руках от лопаты были :D
musuk
22.12.2015 16:19+2Согласен, что с TS intelisense работает лучше. Но и в чистом JS не всё так плохо.
Хотя да, из-за возможной разнородности массива intelisense не срабатывает.
musuk
22.12.2015 10:56+4TypeScript — даёт во-многом иллюзию строгой типизации. Когда вам с сервера приезжает некий объект и вы начинаете верить в то, что это именно IProductsResponse, но проблема в том, что схема объекта может измениться и Typescript вам об этом не скажет.
TypeScript — это как документация, поможет, если её поддерживать, но она и требует кучу накладных расходов на ведение. Нужно писать кучу интерфейсов, только чтобы не писать any. Ибо, ололо, any — это не TypeScript way.
Typescript учит отказываться от изменяемых схем объектов в пользу наследования и это уменьшает гибкость JS. А в JS совершенно нормально получить request и напихать туда полей и получить ViewModel, а в TS надо интерфейсы на всё. В итоге, кода получается больше.
А *.d.ts — это вообще ад: нет для новых версий, нет для непопулярных библиотек. Обновление библиотек превращается в кошмар, ибо надо обновлять *.d.ts для всего этого.
Лично для меня, и в очень большом проекте, TypeScript — это много накладных расходов ради какого-то маленького приемущества над JS в виде Intelisense и чуть лучший анализ кода.
Юзайте es6 — это хорошо.Cyrus
22.12.2015 11:28Поддерживаю, у TypeScript нет TypeScript-way. Набор каркасиков, которые как-то поддерживают код. Хочешь укрепляй, а хочешь брось так. Как правильно транспилить в проекте с gulp? Допустим с помощью gulp-typescript. Для этого надо отключить компиляцию в VisualStudio и WebStorm. Добавить JS файлы в gitignore? Для смешанного подхода — не то. Вообще хоть кто-то коммитит сгенерированные JS? Конкретного ответа нет.
Seekeer
22.12.2015 14:40>схема объекта может измениться и Typescript вам об этом не скажет.
А JS скажет? В случае изменения объекта, код что в JS, что в TS нужно будет менять, только в TS это будет сделать проще.
>маленького приемущества над JS в виде Intelisense и чуть лучший анализ кода.
А мне вот не кажется, что это маленькое преимущество. В JS нужно постоянно помнить, какие поля у меня содержит данный объект и постоянно лезть смотреть в код объявления, как именно там названы поля или функции. Непрекращающаяся боль для меня это.musuk
22.12.2015 16:04+3А JS скажет?
JS не делает вид, что он «строго типизированный». C ТS вы чувствуете себя как бы немного обманутым: интерфейс вы определили, но он ничего не ограничевает, только даёт Resharper'у переименовать поле в случае чего.
Да, это функция полезная если вы саппортите проект, но крайне уныло применять TS, когда у вас быстро развивающийся проект, в котором спека меняется часто.
Потом помните, что хуже отсутствия документации может быть только документация, которая вам нагло врёт. Вот TS вам легко позволит сделать такую. Вам с сервера будет приходить id:string, а в интерфейсе у вас будет id:number или наоборот. Вы очень не скоро поймёте в чём дело, ибо вы будете верить интерфейсам. Чистый JS в этом плане «честнее», он вам сразу ничего не обещает, наоборот, с чистым JS у вас есть безнаказаная возможость менять тип поля и схему объекта в рантайме. Да, может, это не «архитектурно», но, порой, в разы уменьшаяет количество кода и скорость разработки.
А мне вот не кажется, что это маленькое преимущество.
Да, TS говорит о том, что это огромное приемуществно и в теории оно как бы так. Но на лично моей практике, что проще посмотреть в код, чем саппортить кучу интерфейсов.
У меня самая частая операция, это добавление поля в response API. В случае fullstack-js вы добавляете поле в объект mongo + валидатор mongo, и поле уже доступно вам во viewModel ангуляра. А если у вас TypeScript, то по идее вам надо «прокинуть» его через кучу интерфейсов, либо везде писать any.
Хочешь укрепляй, а хочешь брось так.
Если не делать объектам интерфейсы, а писать any, то тогда зачем нужен TS?
Вот у нас корпоративный стайлгайд разработан с требованием минимизировать количество any в коде. Это как бы хорошо, но замедляет разработку.
Хочешь скопипастить пример кода, а он, в 99% случая, на JS. И вот сидишь и делаешь обратную трансляцию из js в ts, определяешь интерфейсы. Тебя постоянно наказывают за модификацию кода необходимостью декларации интерфейсов.
TS превносит рутину в разработку и делает её дороже.
Заголовок спойлераС одной стороны John Papa со своими гайдами, с другой TS с интерфейсами, куды бедному говнокодеру-копипастеру податься…
Alexey2005
22.12.2015 11:18При попытке подружить TS с каким-нибудь экзотическим фреймворком возможны проблемы. Особенно если этот фреймворк самостоятельно генерирует код и html. Попробуйте например использовать Vue.js совместно с TypeScript, энтузиазма сразу поубавится.
Ещё один недостаток TS — сложности с автогенерированием документации.
jsdoc по вполне понятным причинам не работает, а если использовать разного рода костыли для его подключения, в аннотациях приходится дублировать информацию о типах (при том, что тот же WebStorm вполне способен производить проверку типов по аннотациям в чистом JS, и получается почти как язык с типизацией).
Т.е. нужен нормальный инструмент для генерации документации. Инструмент, способный вытаскивать информацию о типах непосредственно из кода, чтоб в аннотации только собственно описание вносить надо было. Пока что с этим проблемы.forcewake
22.12.2015 11:28А в чем, собственно, проблема? Для Vue.js открыто issue на github и люди активно что-то предлагают, например такой вариант vue-typescript
Насчёт доков и jsdoc тоже какая-то натянутая проблема — открываем typedoc, читаем и радуемся.
greybax
24.12.2015 16:10jsdoc по вполне понятным причинам не работает
кстати уже есть пулл реквест который добавляет поддержку JSDoc
FlashManiac
22.12.2015 23:59Недавно изучал TypeScript. Выводы в основном положительные. Но есть ряд вещей которые я так и не понял:
1. Как импортировать другой файл TypeScript, что бы он вкомпиливался в результирующий файл? Т.е. как в обычных языках — пишешь импорт такой то класс и все. А вот с TypeScript такое не пройдет — надо указывать в html дополнительно этот файл. Или есть способ проще и элегантнее без большой писанины?
2. Приватные переменные только проверяются на стадии компиляции — но на самом деле они публичные и если предок и наследник имеют приватную переменную с одним и тем же именем — будет просто ошибка компиляции. Это как то не продумано.
Пробовал в Visual Studio 2015TheRabbitFlash
23.12.2015 09:27-1Как импортировать другой файл TypeScript,
Еще плюс Haxe:
import com.packagename.MySecondClass; ... var m2c : MySecondClass = new MySecondClass();
и он сам всё вкомпилирует в результирующий JS
2. Приватные переменные только проверя..
Снова сравниваю с Haxe
public var myPublic : Int = 0; private var myPrivate : Int = 0; public static var myStaticPublic : Int = 0; private static var myStaticPrivate : Int = 0;
P.S. я понимаю, что речь тут о TypeScript. Но для сравнения с другими языками это полезно знать :) Особенно тем, кто только решает на чем его JS писать :)FlashManiac
23.12.2015 11:41Да безусловно Haxe в данных вопросах лучше. Он делался по образу и подобию AS3. Но он тоже не лишен недостатков — а их у него очень много. И да я пишу на Haxe сейчас. Просто тут обсуждение TypeScript и хотелось бы узнать побольше о нем )
greybax
23.12.2015 11:391. Как импортировать другой файл TypeScript, что бы он вкомпиливался в результирующий файл?
tsc --out D:\ts\output.js D:\ts\app.ts D:\ts\hello.ts
в данном случае 2 файла app.ts и hello.ts скомпилируются в 1 output.js
2. Приватные переменные только проверяются на стадии компиляции — но на самом деле они публичные и если предок и наследник имеют приватную переменную с одним и тем же именем — будет просто ошибка компиляции. Это как то не продумано.
Тут я с вами согласен. Это вызвано тем, что в JavaScript невозможно задать приватные поля. Они просто не предусмотрены спецификацией языка.FlashManiac
23.12.2015 11:48Ну лично я не поклонник командной строки, прописывать каждый файл который надо скомпилить — это тот еще ад. Проще указывать по необходимости из файла в фаил.
greybax
23.12.2015 11:56Если есть возможность компилировать несколько файлов в один, никто не мешает автоматизировать вам этот процесс. Например прописать настройки компиляции при билде в вашем проекте.
hippoage
31.12.2015 17:34Оба вопроса связаны с платформой JS и тем, что TypeScript достаточно тонкая надстройка.
1) импорты появились в ES6, поэтому достаточно TS 1.7 скомпилировать в ES6, а ES6 в ES5. Насколько такая схема сейчас работает с разными видами IDE, систем сборки и версиями TypeScript не скажу.
2) в JS нет приватных переменных, не стали придумывать усложнение, достаточно ошибки сборки
Starche
Спасибо конечно за статью, но получилось сумбурно и непоследовательно.
Действительно ли это доставляет проблем? Говорят, что сгенеренный JS обычно настолько прост, что вообще не составляет проблем его дебажить без всяких сорсмапов. Правда или врут? Если правда, то минус сугубо теоретический.Я как раз перехожу на тайпскрипт и действительно хотел узнать, каковы минусы (о плюсах, как вы и сами заметили, уже сказано довольно много). Полный развернутый анализ плюсов и минусов был бы очень полезен.
Однако вместо этого вы просто вставили довольно очевидную вставку про статическую типизацию, явно для увеличения размера статьи. И ещё цитаты там всякие, что тоже не очень нужно.
В общем, я может и редиска и многого хочу, но вот чего бы я действительно хотел узнать
Это ж браузерные классы, а не тайпскриптовые. Или я чего-то не понял в этом минусе, или вы что-то не то говорите.
Опять же. Насколько это реальная практическая проблема? Действительно ли всякие ленивые люди это делают, и это доставляет какую-то боль?
И опять же хотелось бы примеров — насколько часто такое встречается, и насколько много проблем доставляет.
Вот как-то так. В общем, если бы вы правда расписали проблемы языка с точки зрения практического использования, было бы круто. Ну и плюсы тоже конечно были бы в тему для сравнения, но это второстепенно — про них и правда говорят везде.
Seekeer
На мой взгляд это не проблема при минимальном уровне дисциплины в команде. Хотя, конечно, если использовать any везде, то будет боль. Но записывать это в минусы языка я бы не стал. dynamic же в минус шарпу не ставят.
Если критично использовать последние версии или редкие библиотеки — то возможно будут проблемы с d.ts. Но никто не мешает работать с JS файлами через any или написать свой файл определений.
У меня за полтора годы работы такое было один раз. Пришлось повозиться, но большой проблемы я не вижу.
greybax
Если вы запускаете проект в IE, то такая возможность по умолчанию есть.
Seekeer
Спасибо, не знал.
greybax
Спасибо за столь развернутый комментарий. Постараюсь ответить на Ваши вопросы:
Согласен с вами, что в большинстве случаев хватает дебажить итоговый JS, но в крупных проектах, если у вас есть множество классов, контроллеров, вью моделей, то гораздо приятнее дебажить именно их. Сам сталкивался с такой проблемой, что без проблем получается отлаживать конечный код на ts только в браузере IE. Во всех остальных приходится делать манипуляции с .map файлами, дабавляя их в соответвующую директорию на сервере.
Лично сталкивался со случаем вида (event).keyCode, где keyCode нет в классе Event.
Считаю это плохой практикой, т.к используя any вы лишаете себя основной возможности TypeScript — проверки типов. К примеру описав параметр функции как any, вы должны валидировать ее тип самостоятельно.
Пример — knockoutjs сейчас имеет версию 3.4.0, а в DefinitelyTyped есть определения пока еще только для версии 3.2.0
Starche
Спасибо, не знал, что IE поддерживает ts напрямую. Крутая фича, даже интересно стало попробовать.
Я ж говорю, это исключительно браузерные классы. Откройте любую консоль и поиграйтесь как я.Тайпскрипт тут не может ничего ни добавить, ни изменить.
Этих классов, кстати, вообще не будет, если вы будете писать на TS под NodeJS
greybax
Что вы подразумеваете под браузерными классами? В моем случае если написать следующий код, при компиляции TS вернет ошибку:
Starche
Я подразумеваю, что Event — это часть Web API developer.mozilla.org/ru/docs/Web/API/Event
И да, там нету keyCode, смотрите выше скрин из консоли. Потому что у Event много наследников. И например у WheelEvent нет keyCode. И ещё у многих других его тоже нету.
Ошибка у вас потому что (event) может быть объектом как KeyboardEvent (где есть keyCode), так и например WheelEvent, где keyCode нету.
В общем, нужно честно описывать, какого именно ивента вы ждёте.
Epsil0neR
Лично я, работая с TypeScript с версии 1.3, многократно сталкивался с проблемой неверной/неполной декларации библиотек, но это как я считаю проблема в том, что декларацию чаще всего пишут не сами создатели js-библиотеки, а кто-то постороний и делает это в спешке, т.к. зачастую небывает описаний к функциям или параметрам.