В чём разница между нейтив JavaScript и TypeScript?

Браузеры не поддерживают других языков, кроме JavaScript. Поэтому любой язык будет компилироваться в JavaScript. Помните, несколько выпусков назад мы говорили с вами про обёртки? Так вот язык — это просто более удобная обёртка над какой-нибудь функциональностью. Разные языки предлагают разные возможности: зачастую это сводится к модульности, типизации или особенностям других парадигм программирования. Например:


  • Dart предлагает нам модульность и типизацию.
  • Elm — функциональное программирование и тоже типизацию.
  • Clojure — просто функциональное программирование.
  • CoffeeScript, хм-м…

Да простит бог, тех кто придумал CoffeeScript, они не ведали что творили. Впрочем, стрелочные функции оттуда в JavaScript всё-таки попали. А вот обёртки над классами не будем ставить им в заслугу, потому что слова class и extends были зарезервированы в языке ещё задолго до появления CoffeeScript.


Теперь посмотрим, что нам предлагает TypeScript. В TypeScript есть: модульность, типизация и некоторые фичи, которых не было в JavaScript. Dart предлагал то же самое, так почему же он не взлетел? А TypeScript используется в Angular версии 2 и 4, на которых написано полмира.


Дело в том, что TypeScript использует эволюционный подход. Для того чтобы начать писать на TypeScript, вам не нужно учить новый синтаксис. Создатели языка вообще утверждают, что TypeScript — это надмножество JavaScript. Получается, что любой JavaScript будет валидным TypeScript. Даже те фичи, которых не было в JavaScript, они оформили по стандарту ES2015, с заделом на будущее, чтобы не нужно было переписывать код.


Каким образом TypeScript стал популярен — ясно, теперь давайте разберёмся, чего все так гоняются за этой типизацией, что же она даёт. Дело в том, что типизация есть во всех языках программирования, другое дело какая. Типизация бывает сильная и слабая.


JavaScript использует слабую типизацию. Это когда в любую переменную можно записать любое значение.


let anyVariable = 'It’s a string';
anyVariable = ['No,', 'I’ve', 'changed', 'my', 'mind'];

В TypeScript же используется сильная или строгая типизация. При строгой типизации, когда вы создаёте переменную, нужно сначала сказать, какого типа будет эта переменная. То же самое работает и для параметров функций.


let anyVariable: string = 'It’s a string';
anyVariable = ['I', 'can’t', 'do', 'this']; // Exception

Сторонники сильной типизации приводят два аргумента в её пользу:


  1. Во-первых, это более эффективная работа с памятью;
  2. А во-вторых, это предотвращение ошибок, связанных с преобразованием типов.

Эффективная работа с памятью в случае с TS неактуальна, потому он в любом случае будет скомпилирован в слабо типизированный JavaScript. А вот от некоторых ошибок приведения типов, которые возникают в рантайме, сильная типизация действительно может помочь.


Представьте, что вы программируете онлайн-калькулятор. У вас есть текстовое поле, пользователь вводит туда числа, вы достаёте строковое значение и полученную строку передаёте в функцию, которая подставляет её в математическую формулу.


function getMonthlyIncome(val) {
  return val * 0.055 / 12;
};

Слабо типизированный JS пропустит эту строку в любом виде, даже если она не переводится в число. И в результате таких вычислений пользователь может получить NaN рублей. В TypeScript же вам придётся сначала перевести эту строку в число самостоятельно, а потом уже передать в функцию в надлежащем виде. А если вы забудете это сделать, то вы увидите ошибку ещё на этапе компиляции вашего кода.


function getMonthlyIncome(val: number): number {
  return val * 0.055 / 12;
};

Получается, что какие-то преимущества в строгой типизации всё-таки есть, но не забывайте, что TypeScript — это не единственное решение. В самом JavaScript на уровне функций вы можете добавить дополнительные проверки типов. Да, ваш код будет немного более избыточным, но не забывайте, что другие языки компилируют свои проверки типов примерно в то же самое.


У Facebook есть инструмент для типизации, он называется Flow. Он добавляет систему типов, похожую на систему из языка OCaml, в ваш JavaScript-код. Библиотека Google Closure Library использует хитрый механизм типизации на основе комментариев JSDoc. Вообще, написание комментариев JSDoc, даже без компиляции и хитрой системы типов, поможет вам решить некоторые проблемы. Во-первых, вы сами будете понимать интерфейс тех функций, которые пишете. А во-вторых, некоторые редакторы, которые поддерживают JSDoc, будут подсказывать вам что вы что-то не то передаёте куда-то не туда.


Да и другие языки программирования со строгой типизацией тоже есть. Тот же Elm — он подойдёт вам гораздо лучше, если вам функциональный подход ближе объектно-ориентированного.


В любом случае помните: все эти языки и компиляторы делают ваш проект сложнее в поддержке и настройке, да и кода меньше не становится. Получается, что в их сторону нужно смотреть только в том случае, если накладные расходы действительно того стоят, например, в больших проектах. Если вы делаете небольшой одностраничный лендинг, где почти нет JS и важна скорость загрузки, то лишняя сложность может только навредить.


Видеоверсия



Вопросы можно задавать здесь.

Комментарии (13)


  1. Aingis
    28.09.2017 18:00
    +3

    На картинке Игорь показывает что значит «сахарный».


  1. vil996
    28.09.2017 19:24
    -2

    Лучшее разъяснение разницы между использованием JS и TS.


    1. Aingis
      28.09.2017 19:38

      А я вот не понял, как ручное приведение к числу Number(val) спасёт от NaN, ведь это валидное значение типа number.


      1. devsane
        29.09.2017 12:30

        Имелось в виду, что строгая типизация в больше степени спасает от случайных неточностей, превращая ошибки во время исполнения в ошибки на стадии компиляции. Проверку значения при этом никто не отменяет, и перед приведением типов необходимо самостоятельно убедиться, что данные корректны.

        Получается, если компилятор указывает на какое-то проблемное место — это можно считать как указание, что следует проанализировать поток данных и добавить необходимую валидацию. Если же проблемное место «закрывается» небезопасным приведением типа (в TypeScript такое тоже есть), или небезопасной инициализацией, как в случае с Number(val), то разработчик сам переносит проблему обратно на стадию исполнения и лишает себя преимуществ строгой типизации.


        1. Aingis
          29.09.2017 12:36

          Проверку значения при этом никто не отменяет, и перед приведением типов необходимо самостоятельно убедиться, что данные корректны.

          Точно ли это имелось в виду? В видео ничего про это нет.


      1. KhodeN
        30.09.2017 05:55

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


  1. Scalar
    28.09.2017 20:22
    +11

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

    Уважаемый автор, нет, это не так называется. То, что вы описываете — это «явная + статическая» типизация, а вовсе не «строгая».
    см. habrahabr.ru/post/161205


  1. kahi4
    28.09.2017 21:07
    +7

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

    Если ts может и вставлять какие-то вещи в рантайм (но он так не делает), то наличие того же flow вообще не повлият на выходной размер файла. В чем проблема? Да и сейчас такие лендинги пошли — видео на всю страницу на фоне, а они заморачиваются на 4кб бейбелевского рантайма.


    все эти языки и компиляторы делают ваш проект сложнее в поддержке

    Все эти языки и компиляторы делают ваш проект проще в поддержке. Для этого они и придуманы, а то как-то странно: сложнее разрабатывать, сложнее поддерживать, какой прок тогда?


    Эффективная работа с памятью в случае с TS неактуальна, потому он в любом случае будет скомпилирован в слабо типизированный JavaScript.

    И да и нет. JIT не очень любит, когда функцию вызывают с какими попало типами одних и тех же аргументов, TS провоцирует подумать лишний раз чем делать функцию, принимающую и null и object и number и string. Но не запрещает.


    Тот же Elm — он подойдёт вам гораздо лучше, если вам функциональный подход ближе объектно-ориентированного.

    Elm слишком сильно "втирает" свою архитектуру. Это вообще компилятор-язык-раект-редукс в одном флаконе, что может оттолкнуть.


    А о чем вообще статья? Что бывает javascript, а еще бывают языки, компилируемые в js? И дальше то что, это и так все знают.


  1. hVostt
    28.09.2017 23:50
    +4

    Типизация это далеко не единственное, что даёт TypeScript. Автор написал глупости по-видимому из-за отсутствия опыта участия в разработке средних и крупных проектов. Для хоупейджей и лендингов TypeScript действительно оверхед.

    А вот это шедевр: «В любом случае помните: все эти языки и компиляторы делают ваш проект сложнее в поддержке и настройке, да и кода меньше не становится». Ребята, которые используют TypeScript, знайте — вы глупы, зачем-то делаете свой проект сложнее в поддержке и настройке :)


  1. RUQ
    29.09.2017 10:15
    -3

    Не согласен с мнением про Coffeescript. Не ведали серьёзно? Про class и extend, но по факту их не было, да и много другого в ES забрали из Coffeescript.

    Мне импонируют Coffeescript и… jQuery (кстати, я с Coffeescript познакомился после года работы с TS). Импонирует по одной простой причине — мне кажется код должен быть как можно проще, декларативный стиль понятнее чем императивный. И вот в как раз в этом Coffeescript даёт 100 очков вперёд ES6…

    Ещё удалось попробовать Elm, чуть дальше чем простой Hello world. Но ощущения очень крутые.


    1. Riim
      29.09.2017 19:42

      много другого в ES забрали из Coffeescript

      Почему все обожатели кофе так уверены, что разработчики ES6 смотрят именно на него (кофескрипт)? По сути в кофескрипте я не увидел ничего такого чего не было во всяких питонах, руби и тд., так какого спрашивается вы всюду пихаете это чудо как что-то принципиально новое?


  1. Tim152
    29.09.2017 17:09
    +2

    кофе придумали рубисты, но к чему фейспалм?


  1. Druu
    01.10.2017 11:29

    > Он добавляет систему типов, похожую на систему из языка OCaml

    Вы вообще видели систему типов OCaml? Заявлять, что система типов для типизации существующего кода на динамическом языке может быть похожа на систему типов языка изначально статического — это нонсенс. Эти системы типов решают совершенно разные задачи и, как следствие, разный дизайн.

    Flow (а также тайспскрипт и другие подобные вещи) — про subtyping (опционально — структурный), occurence typing (для того чтобы типизировать динамический код), отсутствует ad-hoc полиморфизм (не выражается в семантике динамических языков), прямые суммы заменены объединениями (но могут быть сэмулированы кривым костылем).

    В окамле — полноценные алгебраики с GADT, ad-hoc полиморфизм, глубокая система модулей (характерная особенность для семейства ML'ей), отсутствие динамических костылей в виде объединений и occurence typing'а