TypeScript как будущее энтерпрайзного JavaScript. Часть 1

Не стану пересказывать тут историю появления JS, она прекрасно всем известна, и описывается одним словом — спешка. JavaScript задумывался и создавался в очень сжатые сроки. По словам создателя JS Brendan Eich, у них было лишь 10 дней на все. Microsoft наступал на пятки и, если бы они проиграли, то сейчас эта статья была бы частично посвящена VBScript (Visual Basic Script).

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

Битва с ветряными мельницами

Браузерный мир выбрал JavaScript со всеми его недостатками, оговорками и поверхностной простотой. С тех пор утекло много воды, сам язык изменился, оброс дополнениями и удобствами, но основные проблемы остались, и избавиться от них почти невозможно, не сломав весь интернет.

Первые веб-сайты были очень просты и статичны. JavaScript использовался лишь в редких случаях для анимации или валидации форм перед отправкой. Проблема заключалась в том, что далеко не все браузеры поддерживали JavaScript. Когда же он стал стандартом для всех популярных браузеров, началась разработка приложений, которые делали в рамках веб-страницы нечто большее, чем анимация бегущей строки или проверка введенных значений на форме обратной связи. Приложения становились больше, и начали давать о себе знать проблемы JavaScript, связанные с типами данных, с отсутствием единого способа наследования объектов, с моделью памяти JS, а также многое другое.

Сам язык способствует написанию плохого кода. И прощает, по крайне мере вначале, написание явной лапши вместо кода. Динамическая природа языка просто подталкивает к написанию универсальных функций, которые могут принимать десятки вариантов аргументов (как по типу данных, так и по их количеству).

Рискую быть закиданным помидорами, так как покушаюсь на святое, но самый популярный пример — jQuery. Стоит хотя бы вспомнить возможные варианты главной функции-объекта jQuery. «Функция-объект» — чувствуете, как это звучит? Вы можете вызвать jQuery как функцию девятью (девятью, Карл!) различными способами — все зависит от аргументов. А еще, сама функция является объектом, в котором может быть неконтролируемое число методов и/или свойств.

Да, jQuery — это действительно швейцарский нож с огромным количеством возможностей по упрощению жизни рядовому веб-разработчику. Но часто на базе системы jQuery-плагинов создают целые приложения интернет-магазина с десятками форм и диалогов. И вот там уже начинается натуральный ад и «лапша-код». Это самый популярный пример. jQuery разрабатывался как средство удобного доступа к DOM, но в итоге получился комбайн и практически отдельный язык программирования, что и порождает целую отдельную вселенную безумия, где на каждый вопрос один ответ — плагин для jQuery.

Да, написано огромное количество фреймворков уровня приложения, которые помогают удержать всю мощь динамичной лапши в узких рамках предложенной/рекомендуемой/требуемой структуры файлов и папок. Только благодаря таким фреймворкам мы с вами еще не сошли с ума окончательно.

В корпорациях вроде Google технические специалисты очень быстро столкнулись с тем, что с ростом размеров JavaScript приложения практически с геометрической или даже экспоненциальной скоростью растут затраты на поддержку и исправление ошибок. В ответ на эту проблему Google выпустил GWT — Google Web Toolkit. Это компилятор, набор инструментов и базовых классов для разработки веб-приложений на Java. Стало возможным с минимальными оговорками писать веб-приложения на строго типизированном языке программирования с использованием большинства его плюшек. В качестве результата вы получаете приложение, написанное на, фактически, машинном JavaScript. Этот код невозможно отлаживать отдельно от GWT, это просто лишено смысла. В декабре прошлого года, после более чем года молчания, проект выпустил бету новой версии (2.8.0).

Стоит также заметить, что GWT чаще рассматривают как единственную возможность для джавистов, не владеющих JS, писать развесистый front-end без отрыва от любимого языка для back-end’а.

Других же не устраивал только синтаксис JavaScript, и они разрабатывали свои варианты языка программирования, которые с разной степенью прозрачности транслируются в JavaScript. Тут список примеров возглавляет, конечно же, CoffeScript. Подборка всего, что так или иначе транслируется в JavaScript, опубликована на github в wiki проекта CoffeScript.

Общий смысл сводится к тому, что вы можете писать front-end приложение почти на любом языке программирования, который вам нравится, важно лишь, чтобы была возможность сгенерировать JavaScript код на базе вашего исходного кода.

ES6

ES6 приходит к нам как набор дополнений к уже привычному стандарту ES5. Набор этих дополнений неточен, постоянно дополняется и переделывается в той или иной степени.

Конечно, ввиду того, что браузеров больше, чем один, и интерпретаторов JS, как минимум, столько же (даже несмотря на общие корни и/или основу у многих из них), каждый из них гнет свою линию и экспериментирует с синтаксисом, с трактованием предложений сообщества, или предлагает свои идеи.

Это своего рода продолжение войны браузеров, но уже в более вялой форме. Вот только она по-прежнему приводит к условиям проверки браузера или даже его версии в нашем коде, всевозможным «полифилам» (polifill), которые мы вынуждены подключать к нашим проектам, если хотим использовать какую-то «вкусность» из ES6, например, Promise или setImmediate. Но это история про браузерный API, а не про сам язык JavaScript.

Если же мы хотим использовать чуть более классические (в сравнении с другими языками) классы, генераторы, не хотим думать о контексте для колбека, то тут уже начинаются проблемы: одно дело — желания современного разработчика, который хочет писать современный код, и, совсем другое дело — реальность брузеров клиентов. Вот тут на помощь и приходят транспайлеры и компиляторы.

Проект Babel представляет из себя транспайлер из современного представления о правильном переводе ES6 или даже ES2015 в код, совместимый с ES5. То есть разработчик получает возможность писать на самой современной версии JavaScript и, в большинстве случаев, не беспокоиться о совместимости с браузерами, которые еще не включают поддержку ES6 в свои JS-движки (или не включают по умолчанию, так как все, что скрыто за специальными экспериментальными настройками, лучше считать выключенным и недоступным). Про проект и все его возможности вы можете прочитать на официальном сайте, а мы пойдем дальше.

Бардак и порядок

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

Когда команда разработки состоит из более чем одного человека, то возникает необходимость в соглашениях — по архитектуре, выбору внешних библиотек, фреймворка или списка фреймворков (мало ли?). Большинство из этих вопросов решается устно за пару митингов и уточняется устно (конечно же документируется, верно?) на последующих митингах.

С началом разработки появляются новые вопросы и трудности — иерархии классов нужно поддерживать здоровыми и четкими. Минимализм интерфейсов крупных компонентов нужно строго документировать и постоянно устраивать внимательное ревью кода, чтобы не пропустить момент, когда все пойдет вкривь и вкось. А это обязательно случится. В какой-то команде/проекте раньше, в какой-то позже, но это случится. И это будет похоже на притчу про лягушку в кастрюле с холодной водой на медленном огне. В чем может быть причина такого развития событий?

Тут я выскажу исключительно свое мнение, которое вы не должны воспринимать как чистую правду или аксиому. Но дело вот в чем: динамическая природа JS подталкивает к излишней гибкости, и это расхлябывает интерфейсы объектов и функций. Со временем ваши функции и конструкторы объектов начинают принимать все больше разновидностей аргументов, объектов разной степени целостности и такая гибкость в итоге приводит к росту числа фантомных багов, которые решаются подпорками то тут то там, что в свою очередь, еще сильнее повышает энтропию в вашем коде.

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

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

TypeScript — надстройка вокруг ES6, ES2015

Пришло время перейти к главной теме. TypeScript — это язык программирования, который является супер-сетом вокруг ES6, ES2015. Разработан в Microsoft и теперь развивается в содружестве с коммьюнити. Даже Google приложил руку в виде AtScript, был поглощен одной из прошлых версий TypeScript. Спросите, если хотите, подробности у Google.

Что из себя представляет супер-сет? Это надстройка вокруг основного языка. Таким образом, любой работающий JavaScript-код автоматически является валидным TypeScript-кодом.

Что нового привносит TypeScript:
— Статическая типизация и выведение типов;
— Необязательные аргументы для функций и значения по умолчанию;
— public, private, protect для свойств и методов классов;
— Геттеры и сеттеры для свойств «без головной боли»;
— Декораторы для всего*;
— Интерфейсы и абстрактные классы;
— Generics;
— Компилирование в ES5 или даже в ES3 (с оговорками).

И в том числе плюшки ES6:
— Arrow Functions;
— Классы с единым стилем наследования;
— async/await из ES7;
— Итераторы и Генераторы*;
— Многострочные строки с шаблонизацией и тоже «без головной боли» с плюсами и кавычками;
— Управление зависимостями, в том числе и их динамическая загрузка.

* - (цель компиляции — не ниже ES5) экспериментальная поддержка, имплементация может измениться.

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

Подавляющее большинство работы по защите вас от вас же компилятор производит именно в момент анализа типов данных и их взаимодействия. Вообще вся история про TS так или иначе сводится к сверке типов данных и интерфейсов объектов. Только после этого начинают работать преобразователи синтаксического сахара. Они чем-то напоминают простые макросы, которые по шаблону переделывают строки (конечно, это грубое сравнение, но оно близко к реальности).

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

Предупреждения — главное оружие компилятора. Через предупреждения, которые он выдает в консоли, он сообщает вам о своих «сомнениях» относительно качества кода — «Вы указали, что эта переменная имеет тип Строка, но вот тут вы используете её как Число, вы уверены?» (это очень вольный пересказ сообщения компилятора). Если вы уверены, и ваш выбор конкретно такой логики осознан, то вы можете такую строчную переменную дополнить приведением типа к числу (или воспользоваться, например, parseInt()), явно сообщая компилятору, что ситуация под контролем.

Весь генерируемый JS-код в результате работы компилятора может быть легко читаемым нормальным JS-кодом, сохранившим имена переменных, объектов и свойств, ваши комментарии в нужных местах — все то, что даст вам возможность легко сопоставить TypeScript-код с JavaScript-кодом для лучшего понимания языка.

Это на самом деле удобно и практично, особенно в самом начале осваивания TS, его внедрения в существующий проект — вы можете писать TypeScript-код и тут же видеть получаемый JavaScript-код.

Предупреждения и ошибки компиляции

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

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

Лишь в ближайшее время компилятор TypeScript научится использовать в своей работе JavaScript-код (то есть код в файлах .js) — это позволит расширить сферу его возможностей к анализу на jsDoc-комментарии, где часто можно встретить в том числе типы данных для переменных, аргументов и непосредственному выведению типов на основе кода.

Любой JavaScript — это валидный TypeScript. Так как это супер-сет вокруг JavaScript, это означает, что вы можете использовать все, что есть в JavaScript всех версий, и то, что привносит непосредственно TypeScript.

Статическая типизация и выведение типов

У вас есть базовый набор типов JavaScript с явными декларациями, плюс парочка дополнительных, вроде enum(множество) и tuple (тьюплы, схожие по концепции с таковыми в python).

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

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

Например:

function sum(a, b: number){
 return a + b;
}

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

Но если волей программной логики вы вынуждены реализовать функцию, чей результат по типу может быть очень разным (строка, логическое, объект, уж не знаю, как вам вообще такая идея пришла в голову, но да ладно), или размеры функции не позволяют, окинув её взглядом, понять, какой тип данных она вернет, то его лучше указать явно, даже если компилятор вас об этом не просит (он смог вывести тип результата).

Также TypeScript, как говорилось ранее, оставляет вам возможность использовать все богатства динамического языка и позволяет вводить особый тип данных any. Этот тип данных говорит компилятору буквально следующее: «В этой переменной может быть все что угодно».

Необязательные аргументы для функций и значения по умолчанию

Без предисловий, пример, который расскажет сразу все:

function F1(
 a, b: number,
 c: {name: string},
 d: boolean,
 ...otherParams: string[]): void { .. }

function F2(
 a, b?: number,
 c?: {name: string} | number | string): void { .. }

function F3(
 a, b?: number,
 C = 10): number { .. }

Кроме объявления типа или структуры (что по сути является типом, но без имени) аргумента, в F1 используется конструкция для функции с неограниченным количеством аргументов (при вызове). Фокус состоит в том, что в переменную otherParams будут помещены все прочие (после четвертого) аргументы, с которыми будет вызвана функция. Конечно, для этого будет сгенерированы несколько строк JS-кода, которые любезно отделят эти аргументы из arguments в массив.

F2 описывает случай, когда в аргументах функции есть необязательные элементы — <имяПеременной>?. Это означает, что для этих параметров при вызове функции компилятор не будет напоминать в предупреждениях о несоответствии заголовка функции её вызову. Переменная c — мало того, что необязательная, так еще и описывает несколько вариантов своего типа. То есть эта переменная может быть универсальной по типу — компилятор проследит, чтобы только эти типы данных использовались при вызове функции с этим аргументом.

F3 показывает пример с аргументом, который имеет значение по умолчанию. Синтаксически здесь все просто, с точки зрения генерируемого JS-кода тоже — создается условие, проверяющее аргумент на существование, если аргумент не определен, ему присваивают это значение.

Как видите, все то, что раньше нам приходилось снова и снова повторять в своем JS коде, простейшие конструкции, в которые иногда все же закрадывались досадные опечатки, теперь можно не писать. Синтаксический сахар TS помогает сделать код понятней и наглядней.

Те из вас, кто знаком с языком Python, могут спросить, почему авторы не пошли дальше и не добавили передачу аргументов по имени, примерно вот так:

let x = F3(a = 1, c = 3);

Я, конечно же, выскажу только свое мнение, я даже не знаю, обсуждалась ли такая идея среди разработчиков языка. Но у этой идеи есть явная проблемная сторона — реализовать такой синтаксис возможно через оборачивание всех аргументов в объект. Но тогда такие функции будут потеряны для внешнего кода написанного на JS. Хотя, конечно, можно представить заглушку и на этот случай, но тогда генерируемый код станет существенно сложнее, да и будет сложнее сохранить прозрачность трансляции и увеличится риск коллизий в именах аргументов и полей в передаваемых структурах. Что если внешний JS код вызывает такую функцию и в первом аргументе передает объект в котором есть поля, чьи имена совпадают с именами аргументов функции? Вводить запрет на «первый сложный аргумент функции»? Это выглядит, как минимум, странно.

Public, private, protect для свойств и методов классов

Об этом пункте можно было бы рассказать в разделе «Без магии, или Контроль над ситуацией».

Конечно же, в объектной модели JavaScript в прототипах объектов не существует понятия доступности поля из потомка или потребителя. И TypeScript не добавляет его через хитрейшие сокрытия переменных в областях видимости. Все проще. Если конкретное поле или метод класса вы описали как private, но чуть позже пытаетесь обратится к нему извне, то компилятор скажет вам об этом. Но опять же, несмотря на предупреждение в консоли при компиляции, компилятор послушно сгенерирует обращение к этому полю объекта в JS-коде.

Геттеры и сеттеры для свойств «без головной боли»

Тут все просто — вы используете один синтаксис get name(){}, а TypeScript генерирует для вас способ определения таких свойств через стандартный Object.defineProperty. При этом вам доступен и вариант с вычисляемыми именами таких свойств.

Декораторы для всего (ES7)

Это экспериментальный функционал, доступный при включении опции —experimentalDecorators и при компиляции в JS версии не ниже ES5

Декораторы — это синтаксический сахар и паттерн одновременно.

В ранних версиях TS предлагалось использовать аннотации, но от этого отказались в пользу декораторов.

Аннотации — как это было (или могло быть)

Аннотации — это пометки на сущности. Выглядело это примерно вот так (в старых версиях TS и AtScript, откуда это и пришло):

function annotate(obj){...}
// TS
@annotate
class A {...}

А теперь JavaScript:

// JS
function A(){};
A.__annotations = [annotate(A)];

// или
function A(){};
A.annotations = [annotate(A)];

То есть к объекту прикреплялось дополнительное свойство __annotations или annotations, которые можно было использовать по своему усмотрению. Вы заметили это «__annotations или annotations»? В этом и скрывалась проблема, различные имплементации допускали разные варианты, что вводило путаницу. Проблема усугублялась еще больше, если существовал внешний код, который мог использовать эти свойства, но не знал, какой именно вариант нужно искать в объекте, если вообще знал, что нужно что-то искать, в итоге применение такого сгенерированного кода в модуле написанном на JS, обрастало условиями проверок вида аннотирования, что не способствовало качеству кода.

Декораторы

Декораторы в свою очередь «декорируют» объект, оборачивают собой сущность и, если нужно, подменяют её.

Суть проще продемонстрировать на простом примере. Представим класс, который предоставляет доступ к некой админке и кратко выглядит вот так:

class AdminPage {
 isAuth: boolean = false;
 isRoot: boolean = false;

 @guest( { ifauth_redirect_to: 'home' })
 public login(){..}

 @auth
 public fetch(order: string[]){..}

 @auth
 @rootUser
 public destroyUniverse(){..}
}

Декораторы в этом примере описывают уровни доступа текущего пользователя к конкретным методам класса:
— Метод login доступен гостю, иначе перенаправить на страницу home;
— Метод fetch доступен только авторизованному пользователю;
— Возможность вызвать конец света методом destroyUniverse дана только авторизованному пользователю с правами рут-пользователя.

Такой стиль класса и использования декораторов должен вызвать чувство дежавю как минимум у питонистов и джавистов. Они привыкли к такому подходу.

Долго не задерживаясь, давайте посмотрим на имплементацию декоратора guest:

function guest(options: { ifauth_redirect_to: string | boolean } ={ ifauth_redirect_to: false }) {

    // place for any logic with options before return function generator

    return function(target: any, methodName: string, desc: PropertyDescriptor) { // 1

        let origin = target[methodName];

        target[methodName] = function() {
            if (this.isAuth && options.ifauth_redirect_to) {
                this.redirect(options.ifauth_redirect_to);
            } else {
                origin.apply(this, arguments);
            }
        }

        return target;
    } // 1
}

Итак, функция декоратора должна вернуть функцию, которая будет вызвана для объекта декорирования при создании объекта.

В случае декорирования метода класса функция-результат работы генератора декоратора получит прототип объекта, строчное имя метода и описание метода, если оно существует.

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

Возможность ответить на вопрос «Как применять декораторы в реальной практике и зачем они вам нужны?» я оставлю вам. Эта концепция имеет очень мощную основу и может существенно повлиять на архитектуру вашего приложения.

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

Интерфейсы и абстрактные классы

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

Приведу сразу объемный пример с комментариями, где я постарался использовать почти все:

interface C {
    abc: boolean;
}

interface D {
    dd: number[];
}

abstract class B { // компилятор "не позволит" создать экземпляр этого класса
    constructor(public name: string) {
        // аргумент name в конструкторе описан так,
        // чтобы автоматически было создано свойство name
        // с публичным уровнем доступа
    }
    test(a, b) {
        return a === b; // для этой функции типы не нужны
    }
    abstract length(a, b: string): number // класс потомок обязан
                                          // имплементировать этот метод
                     // или объявить его снова абстрактным (как и сам класс)
}

class A extends B implements C, D {
    static x: number = 5
    private abc = true
    public dd = [10, 11]
    constructor() {
        super(“A”); // компилятор будет настаивать, чтобы в первой строке
                    // конструктора вызвали конструктор предка
    }
    length(a, b: string): number { // обещанная имплементация
        return (a + b).length;
    }
}

Использование интерфейсов в TypeScript откровенно привносит порядок в безумный мир динамического программирования на JavaScript. Конечно же, при компиляции от интерфейсов не остается и следа. Но пока ведется разработка, они помогают контролировать ситуацию, избегая дублирования свойств и методов, поддерживая соглашения между различными частями системы, предоставляя возможность IDE строить адекватные предположения и подсказки.

Еще пример (взятый из официальной документации):

interface IShape {
    color: string;
}

interface ISquare extends IShape {
    // интерфейсы наследуются простым объединением
    sideLength: number;
}

// создание переменной с пустым объектом, но с указанием его типа или типа структуры
let square = <ISquare>; { };
square.color = "blue";
square.sideLength = 10;

// попытка добавить новое свойство
square.a = 1;
// вызовет предупреждение -- этого свойства нет ни в одном
// из интерфейсов.

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

А теперь, интерфейс для функции (взятый из официальной документации):

interface SearchFunc {
    (source: string, subString: string): boolean;
}

let mySearch: SearchFunc;

mySearch = function(source: string, subString: string) {
    let result = source.search(subString);
    return result != -1;
}

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

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

Generics

Непростой функционал, хоть в базовом случае и работает очень просто. Пример из документации:

class GenericNumber<T> {
   zeroValue: T;
   add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();

myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) {
   return x + y;
};

Как и в случае с интерфейсами, лучше прочесть главу в документации для полного понимания. Если очень кратко: компилятор подменяет T в декларации класса на number и перезапускает анализ, будто у класса там везде number. Вот и все. Опять же, до JavaScript-кода вся эта магия (как же я старался избегать этого слова) не доходит, все проверяется/сверяется/выводится до трансляции в JS-код.

Компилирование в ES5 или даже в ES3 (с оговорками)

Тут все просто, компилятор имеет внутри себя заготовки различных конструкций, вроде наследования, в виде шаблонов или кусков синтаксического дерева (это не важно), для различных версий стандарта EcmaScript (из списка поддерживаемых).

Оговорки касаются экспериментальных конструкций вроде декораторов и того, что просто невозможно описать в конкретной версии EcmaScript. Например, ни декораторы, ни set/get для полей класса нельзя описать в стандарте ES3 — просто в этом стандарте нет нужных вызовов в API примитива Object.

Выбор цели компиляции, гарантии, что будут доступны в качестве цели и будущие версии EcmaScript, — это делает TypeScript чуть ли не серебряной пулей. Вы уже можете использовать все то, что придумано нового в синтаксисе JavaScript, использовать проверку типов, декларации интерфейсов, абстрактные классы, декораторы и т.д. И в момент, когда «бизнес решит», что браузеры клиентов уже готовы для ES6 или ES7, вы просто переключите компилятор на другую цель, и генерируемый код обретет новые конструкции, избавится от каких-то подпорок для обратной совместимости. Код потенциально даже может стать быстрее, так как вместо явных обходных путей будет использовать нативное API движка JS.

ES6 в TypeScript

Как было сказано в самом начале, TypeScript является супер-сетом вокруг JavaScript. Это значит, что он включает в себя все синтаксические конструкции, которые добавлены в JS в ES6. Я не вижу смысла освещать их здесь, это заметка все же про TypeScript.

Выводы

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

Внесите порядок и структуру в ваш код и ... (тут допишите свой вариант рекламного лозунга).

Конечно, компилятор не может защитить вас от архитектурных ошибок. Но может предупредить о возможных несоответствиях между задуманным (интерфейсом) и реализацией (классом, функцией, структурой). Типизация переменных и аргументов поможет быть уверенным, что вы правильно прочитали интерфейс и применяете сущности правильно, а не руководствуетесь лишь своим внутренним чутьем. Декораторы могут существенно повлиять на сам подход к оформлению классов и архитектуры в целом. Шаблоны классов (generics), абстрактные классы, помогут не допустить потерю контроля над архитектурой приложения. Ну и весь прочий синтаксический сахар облегчает жизнь и делает код более выразительным.

Во второй части расскажу о тонкостях процесса разработки на TS и миграции уже существующего кода, а также о планах развития TypeScript.

Все про українське ІТ в телеграмі — підписуйтеся на канал DOU

👍ПодобаєтьсяСподобалось0
До обраногоВ обраному1
LinkedIn

Схожі статті




77 коментарів

Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.

Фак написал столько буковок про нативный JS и вкладка крашнулась( с Lazarus на пару)
Прийдется в кратце, нет желания снова расписывать.

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

Начало статьи про спешку. В те сивые времена как только языки не изобретали, Java разрабатывали для бытовых устройств, php был просто библиотечкой одного программиста. Разве что C имел серьезное подспорье.

А далее «сам язык способствует написанию плохого кода», играть надо уметь — классик говорил. Большинство людей не знает как работать с this, а вы про лапшу.

Жесткая иерархия в JS используется ограничено, ведет к блокирующим операциям(сами подумайте почему, лень снова расписывать столько текста).

Статическая типизация и выведение типов
JS не PHP. В Python, Ruby, PHP, Lisp, Erlang она тоже есть, негатив мы слышим в основном из-за PHP. В JS строка имеет в прототипе объект String и он не прыгает при любом телодвижении в Numeric, в большинстве случаев вы получите ошибку, так как у переменной просто не будет нужного метода. Преобразование происходят обычно при операциях где это преднамеренно предусмотрено, таких как например конкатекация приведенная в примере. В случае с конкатекацией это избавляет от рутины необходимой для преобразования типов, которую точно для этой операции нужно будет делать, при этом оригинальная переменная сохранит свой тип. А например запрос у цифры свойства length, гарантировано выдаст ошибку.
Интерфейсы и абстрактные классы
Интерфейсы да, абстрактные классы — apply, call и прочие. В JS если много паттернов которые просто не имеют служебного слова с их названием, тоесть если нет слова abstract или слова destroy, не значит что этого функционала нет вообще.
Public, private, protect для свойств и методов классов
А вот и не правда. В жс есть это, и всегда было, например приватные переменные реализуются областью видимости конструктора. Этот подход более гибкий чем использование привычных бекендщикам public, private, protect. Конечно более гибкий подход требует большей кваливикации.


И так далее. Для реальной ценности статье не хватает сравнения с альтернативными нативными способами. В текущем виде это только статья-аргумент в холиваре для привержеников TS.

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

не только в пыхе + и . помогают интерпретатору определиться как преобразовывать.

вот древний MUMPS (mumps.sourceforge.net/docs.html#OPERATORS)
«A» _ «B» -> «AB»
1+1 -> 2

причем
«1ab» + «1d» -> 2 (кажется и «a1b» + «d1» -> 2, но уже не помню точно)
«1ab» _ «1d» -> «1ab1d»

ну и понятно что
«1ab» + 1 -> 2
«1ab» _ 1 -> «1ab1»

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

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

Неизвестно почему так было сделано, но не слышал чтобы это доставило кому-то регулярные неудобства.

обычное дело, любой привыкший к своему основному ЯП неудобств уже не замечает.

у него уже на уровне рефлексов вырабатывается привычка их обходить. :)

вот упомянутый MUMPS например позволяет писать операторы одной буквой.
профи и писали. никаких неудобств в читабельности


PLoad(Routine,Paramete,i)	
	n G,R,Id s G="",Id=""
	i i="" x "s G=$$"_Routine_"(Parameter)" d  i 1
	.s Id=$o(^COMtmp(%Session,"%Image",""),-1)+1,(^(Id))=""
	.k ^COMtmp(%Session,"%Image",Id) m ^COMtmp(%Session,"%Image",Id)=@G
	e  s Id=$p(i,r1,2),i=$p(i,r1)
	s R=$$LoadMemo($na(^COMtmp(%Session,"%Image",Id)),.i)
	i i="" k ^COMtmp(%Session,"%Image",Id) q r_R
	q i_r1_Id_r_R

Согласен, но в моем арсенале около 5 современных языков, с тремя работаю регулярно. В том числе и

негатив мы слышим в основном из-за PHP
Этот язык из тех что использую и проблемы с типизацией чувствую там достаточно хорошо.
Исходя из выше описанной логики, в JS должно быть тоже самое.


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

Я всего лишь намекнул что аргумент — привык, не чувствую — психологический а не технический

О господи, опять из-за новой технологии подняли холивар на холиваре. Просто прочтите документацию и все споры мигом исчезнут. Javascript ограничен, это уже давно признают. Поэтому и появился Typescript. Точно так же, как php с динамической типизацией со временем эволюционировал в php от фейсбука со статической. Хайп по динамическим ЯП, начавшийся в 2000-х уже прошел, не надо больше.

Javascript ограничен, это уже давно признают
Я б сказав, що скоріше обмежений той, хто таке каже. Його можливостей повністю достатньо для тих задач, які вирішуються за його допомогою. Якщо вам недостатньо, значить ви або обрали неправильну технологію, або не розумієте концепцію JS.

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

а тем временем Angular 2 сменил свой статус на RC1

Ага, я вчера открыл их “5 MIN QUICKSTART” angular.io/...ts/latest/quickstart.html и понял, что я наверно не понимаю что такое пять минут, quickstart и “super-simple Angular 2 application in TypeScript” :)
А еще джуниоров жалко стало... :)

На копіпастінг їх приклада як раз 5 хвилин і вистачить :)

Там только минимум минут 15 нужно, чтобы разобраться что к чему в общих чертах.

Там же все елементарно! :D Спочатку конфігурація та налаштування оточення, а потім пишемо вже додаток. В останні 10 секунд з тих 5 хвилин :)

ко мне этот стих прилип:

В клофелиновом угаре
Я пишу на ангуляре.
Если ж вмазать сразу две,
То пишу на тайпскрипте.
@_h4_

Хорошая статья.

Я пишу на TypeScript уже почти год. Продуктивность разработки значительно выше, чем в JavaScript. Отличная поддержка IDE (WebStorm, Visual Studio Code, etc.). Static code analyzer постоянно подсказывает об ошибках и предлагает autocomplete.
Генерируемый JavaScript понятен.
Наличие source maps позволяет отлаживать TypeScript прямо в броузере, хотя и выполняется JavaScript.
Тот факт, что Angular 2 написан на TypeScript и что Google рекомендует использовать этот язык для написания приложений на Angular 2 сделает этот язык популярным.
Опять-же его легко освоить программистам на Java и C#.

А когда-то вы спрашивали что такого умеет ангуляр и не умеет ExtJS. Что же изменилось?

Тогда я писал об AngularJS. A сейчас я пишу об Angular 2. Это совсем другой фреймворк.

IDE отупляет. А duck typing — наше всё.

Google рекомендует
Кроме того, Google разработал Dart и неслабо контрибьютит в спецификацию ES. Это всего-лишь playground для отладки новых фич ES. Скорее допилят WebAssembly (и компиляцию любого языка в него), чем TypeScript станет самостоятельным языком. www.infoworld.com/...n-browsers-this-year.html

Где вы заметили намек на шанс выделения TS в самостоятельный яп? Об этом речи нет.
WebAssembly вспомнили... горячее с красным замешиваете.

  • WebAssembly это про «максимально быстрый процессинг чего-то на клиенте» (например модных нынче ботов),
  • TS это про «максимально строго, структурировано и удобно для поддержки большого и сложного браузерного приложения». Вы пишите развесистый почти Java/C# код, а на выходе получаете нормальный JS. В таком ключе, если GWT это JS для джавистов которые не смогли JS, то TS для тех фронт-эндщиков, которые прошли все круги ада обычного JS и прозрели.
А Dart скоро закопают...

“WebAssembly is a tale of four browser vendors, seeking __new languages__ and
capabilities while staying fast, secure and portable”

То есть скорость работы — это побочная составляющая, не являющаяся целью создания WebAssembly.

“Languages: C/C++ to start with, but we want to be polyglots.”

llvm.org/...ssembly-HereBeDragons.pdf

А Dart закопают, да. Вместе с TypeScript. Их просто похоронит нашествие адептов Java и C#. Да и других языков.

Что-то я не замечаю нашествия джавистов с GWT на перевес... Как и C#, в прочем.

Вы сравниваете горячее с красным.
С таким же успехом asm.js должен был вытеснить всех. Но как-то вот, не пишут на С развесистые UI для веба. И на WebAssembly не будут писать. Будут писать только игровые движки и прочий чрезвычайно ресурсоемкий процессинг.
А вот бизнес-логику развесистых UI-приложений, будут продолжать писать на JS и все что рядом.

То есть скорость работы — это побочная составляющая
значит ради скорости разработки?

ну тогда будет нашествие не джавистов и дотнетчиков — а пыхеров :)

PHP -> WebAssembly — это да, это будет бомба!

по скорости разработки то, особенно х-як, х-як, пых джаве-шарпу — не оставит шансов на мейнстрим ;)

режим зануды

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

не будет так как найбольшая проблема дальнейшей оптимизации JS это отсутствие статической типизации
не-а. это придумали адепты статической типизации :)

Главные недостатки JS вполне хорошо описаны у Крокфорда в «JavaScript. Сильные стороны».

но если все будут ее там использовать, падает скорость разработки
точно могу сказать о Джаве — в ней ООП уже ощутимо слабее чем в PHP. Более «низкоуровневое». Так что даже если обязать команду пыхеров везде с типами писать — все равно будут быстрее писать чем джависты.
не-а. это придумали адепты статической типизации :)

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

Главные недостатки JS вполне хорошо описаны у Крокфорда в «JavaScript. Сильные стороны».

Единственное хорошее описание у него в том, что язык был построен на тяп-ляп за пару дней. Остальное неадекватно. Он обходит и проблему слабой типизации (слабой, а не динамической), и кривой парсер (молча говоря "метку нельзя уносить на следующую строку от break), и перемешанные массивы с объектами, и операции, которые вместо ошибки выдают любую чушь, лишь бы выполнение продолжалось...

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

Что же до ваших замечаний о Крокфорде и JS — то они туда же мимо.

Время самый невосполнимый ресурс. Поэтому скорость разработки первейший критерий в большинстве случаев.

Хренак-хренак и в продакшн детектед. :(
Впрочем, если ваша целевая ниша именно такая, то не буду больше отвлекать от столь важных занятий.

Что же до ваших замечаний о Крокфорде и JS — то они туда же мимо.

Ну да, я-то целюсь на то, что хотя бы год проживёт :)

Ну да ж, вы мой код ревьювите уж более 20 тм лет. Детектор у вас уже конечно натренировался :)

Ну да, я-то целюсь на то, что хотя бы год проживёт :)
если вы думаете что ЯП сходят с арены когда у них ошибка в парсере при обработке break с меткой, то это говорит всего лишь о вашем узком кругозоре :)
говорит всего лишь о вашем узком кругозоре
В Нетча й вузький кругозір? Бги-ги-ги-ги... :D

через пару годиков узнаем — по судьбе js

я же пока видел что пророчества о скорых похоронах какого-нить ЯП по академическим критериям — оказывались туфтой.
что не мешает людям с узким кругозором применять их и далее. и опять с тем же качеством прогнозирования.

js нікуди не дінеться. А Валентин казав не про ЯП, а про код або проект.

и гыкод, и х-як, х-як и в продакшн тоже никуда не денутся.

хотя я тоже не об этом говорил. да кого это уже интересует?

Ну да ж, вы мой код ревьювите уж более 20 тм лет. Детектор у вас уже конечно натренировался :)

Код не видел, а вот ваши постинги сюда — однозначны. Если вы играете другую виртуальную личность — ну что ж, не удивляйтесь результату :)

если вы думаете что ЯП сходят с арены когда у них ошибка в парсере при обработке break с меткой, то это говорит всего лишь о вашем узком кругозоре :)

Я говорил про код, а не про язык. Язык и не с таким десятки лет живёт, история IT тому сплошные примеры.

Код не видел, а вот ваши постинги сюда — однозначны.
ваши тоже. у меня тоже тьма маркеров для постов :)

возвращаясь к вашему хмыку о важности скорости разработки — зайдите в тему о выгорании например — и убедитесь о прессинге временем на обычных программистов.

то бишь — в большинстве проектов — оно, время разработки(сюда я отношу и время по поддержке кода) критично, но ваши мифические «нормальные программисты» об этом наверное не знают.
они якобы об эффективности выполнения в рантайме думают?

они якобы об эффективности выполнения в рантайме думают?

По необходимости — да. Также по качеству сопровождения. См. ниже.

возвращаясь к вашему хмыку о важности скорости разработки — зайдите в тему о выгорании например — и убедитесь о прессинге временем на обычных программистов.

Прессинг времени на начальную разработку — это специфика некоторых контор. Пусть даже они занимают 80%.
Хвала мне или позор, выбирайте сами, но я никогда не работал в аутсорсе/аутстаффе. Только в продуктовых. Поэтому, да, некоторой специфики не испытал, и для меня цена последующей поддержки выше скорости разработки.

Выгоранию это, кстати, не мешает — после 10 лет работы с VoIP я на него даже издалека смотреть ненавижу.

у меня тоже тьма маркеров для постов :)

И как, они помогли угадать то, что я сейчас описал?

Пусть даже они занимают 80%.
тогда это — норма.
потому что утрировано — норма это когда большинство.
то есть вот эти 80% — и есть нормальные прораммисты.
а ненорамальные — это программисты из NASA которым на вылизывание кода для очередного спутника дается 2-3 года.

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

Хвала мне или позор, выбирайте сами, но я никогда не работал в аутсорсе/аутстаффе. Только в продуктовых
тогда я правильно сказал об узком кругозоре.
в продуктовых компаниях работает меньшинство программистов.
большинство программистов пишет и сопровождает уникальные, заказные проекты. даже когда суть этого кода — всего лишь интеграция разнообразных программных продуктов.
И как, они помогли угадать то, что я сейчас описал?
выше написал как.

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

то есть по классике
Специалист подобен флюсу: полнота его односторонняя

тогда я правильно сказал об узком кругозоре.

Даже если так — выводом из него приписали мне чужое утверждение про 1 год жизни JS. Что автоматически дискардит оценку кругозора. Впрочем, я согласен с ней, в изложенном далее виде и на другой почве :)

то есть вот эти 80% — и есть нормальные прораммисты.

russian.joelonsoftware.com/Articles/FiveWorlds.html

актуальность не ушла.

актуальность не ушла.
да, не ушла.

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

а насчет времени добавлю что оно как ограничение есть во всех пяти мирах.
другое дело что конкретная цифра зависит от горизонта планирования бизнеса, для которого создается ПО.

попросту — «дорога ложка к обеду» даже в случае «программистов NASA».

и для продуктовых компаний тоже — вопрос в виде обслуживаемого бизнеса и принятых там типичных измерениях времени «дни», «кварталы», «годы».
если это компания из топов медицинско-диагностического оборудования — то плюс/минус год — роли не играет.

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

поэтому даже:

я никогда не работал в аутсорсе/аутстаффе. Только в продуктовых.
тоже не очень показательно.
на какой бизнес ориентированы были эти продуктовые компании, вот в чем вопрос :)

Когда вам надо подключить стороннюю библиотеку (js либу) — вы используете d.ts или прямо в коде export? Или как вы это решаете у себя на проектах?

ps: не все ’DefinitelyTyped’ up-to-date.

.d.ts и да, полнота оставляет желать лучше, но это Open Source — подключайтесь.
Переустановите у себя tsd, вас ждет сюрприз в консольном выхлопе.

tsd is deprecated. Используйте Typings.

Вы испортили сюрприз ))

А еще один сюрприз — новая версия Typings переименовывает выкачанные определения в index.d.ts. И в ответ на зарепорченный баг автор Typings ответил, что так и надо и нечего референсить индивидуальные файлы определений.

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

Та как-бы не сюрприз давно, используем angular2 на ts и такие сюрпризы уже стали обычными буднями.

Возможно излишне придираюсь, но пару моментов по поводу EcmaScript в статье режут глаз:

Проект Babel представляет из себя транспайлер из современного представления о правильном переводе ES6 или даже ES2015 в код, совместимый с ES5
Чем автор отличает ES6 от ES2015?
Декораторы для всего (ES7)
Декораторы не являются частью ES7 (ES2016). ES2016 включает в себя всего 2 обновления (те, что находятся на stage-4 по TC39)

Вот тут об этом немного подробней

о правильном переводе ES6 или даже ES2015
Чем автор отличает ES6 от ES2015?
та да, похоже данного куска он и не автор вовсе
Этот код невозможно отлаживать отдельно от GWT, это просто лишено смысла.
Це до тих пір пока “ежа с ужом” не почнуть схрещувати.
Наприклад: компонент на GWT потрібно звязати в аплікусі з компонентом на голому JS. І все — почитаєш лазити по тому воно нагенерувало. Писати JSNI вставки і т.п.
Я, правда, чорт знає ще коли з цим возився — може вже й багато змінилось.

Сильно голосний заголовок, можливо так, але не на разі.

Я бы сказал, что это уже настоящее. Я сам не большой фанат TS, но по количеству entrprise проектов в аутсорсе, которые в моем окружении перешли за последний год на TS особенно там где используеться МС стек это подтверждают полностью. Фидбеки вполне положительные, для enterpirse и крупных веб-проектов инструмент очень ок показывает себя.

Согласен. Но вообще достаточно самому попробовать, и сразу все станет понятно. Даже ES6 не сравнится по удобству, об обычном джаваскрипте и говорить нечего.

Чуть более развернутая статья того доклада, который Андрей Дерень проводил на iforum2016. Там тоже задавались вопросы «TypeScript надстройка для Джавистов» или «в ES6 всё это есть, к чему теперь TypeScript»... но MS и Google ставят упор на TypeScript, так что уверен, что будущее у него есть.
От себя скажу, что после Java, даже не для «джедая», TypeScript легче осваивается нежели JS.

Но все равно от:

<quote>Также TypeScript, как говорилось ранее, оставляет вам возможность использовать все богатства динамического языка и позволяет вводить особый тип данных any. Этот тип данных говорит компилятору буквально следующее: «В этой переменной может быть все что угодно». </quote>,

<quote>Если конкретное поле или метод класса вы описали как private, но чуть позже пытаетесь обратится к нему извне, то компилятор скажет вам об этом. Но опять же, несмотря на предупреждение в консоли при компиляции, компилятор послушно сгенерирует обращение к этому полю объекта в JS-коде.</quote>

<quote>Что нового привносит TypeScript:
...
— Интерфейсы и абстрактные классы;
и чуть ниже там же:
Интерфейсы и абстрактные классы
Ни интерфейсов, ни абстрактных классов в JavaScript нет, как и нет разумных аналогов их представления.</quote>

глаза, после джавы, все-таки слезятся.

а мне статья понравилась, жду продолжения. спасибо!

Сейчас композиция популярнее чем наследование, покр мере в ЖС мире. Большую часть проблем решают хорошо написаные тесты. Которые всеравно нужно писать.
Реально в моей практике проблем с типами раз 5 за 7 лет.
Тайпскрипт — это хороший пруф оф консепт, возможно вкусные части войдут в es.next, например декораторы функций могут быть очень мимими.
Но я бы не ставил на тайпскрипт.

А были какие-то разговоры о внесении в ES.next возможностей статической типизации (я правда не в курсе, если что)?

ИМХО одна из ключевых selling points TypeScript — это именно проверка типов на этапе компиляции. Привыкнув к ней, при написании кода на обычном JavaScript чувствуешь себя как на костылях.

сейчас еще есть Flow которые вносить намного меньше изменений, но дает тоже самое (именно проверку типов)

Есть только для Linux и Mac. Требует отдельно babel с собственным экстеншином для удаления деклараций типов... Весьма странная штука. Полумера, я бы сказал.

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

в ES.next возможностей статической типизации
Нет — думаю что статической типизации не будет
Привыкнув к ней, при написании кода на обычном JavaScript чувствуешь себя как на костылях.
Мне кажется это утверждение черезчур опиниейтед, я к примеру всегда себя неуютно чувствовал в типизированых языках — более половины моего времени уходило на приведение типов.
Да и реально нет проблем с типами, но есть много страхов, и да — чуваки которые приходят из стат типизированых языков чувствуют себя реально неуютно. Так что мне кажется что эта фишечка для комфорта, но ее объективная ценность сомнительна.

Прелесть TypeScript в том, что он не заставляет тебя писать «типизированный» код. Хочешь — объявляй всё как any и пользуйся всеми прелестями динамических языков, а хочешь — объявляй конкретный тип и пользуйся проверкой типов на этапе компиляции.

реально нет проблем с типами, но есть много страхов

Я бы так не сказал, когда имеешь дело со сложными API типа SharePoint JSOM. Очень добавляет уверенности, что ты, скажем, не полезешь вычитывать свойство, которого в переданном тебе контексте просто нет.

более половины моего времени уходило на приведение типов

вы могли бы описать конкретную ситуацию?

Реально в моей практике проблем с типами раз 5 за 7 лет.
предположу, что вы говорите больше про проблему 4 + «3».
Я же подразумеваю — интерфейсы классов, структур и функций. Строгое соответствие интерфейсу создаваемого класса. Я могу описать логику в интерфейсах и отдать коллеге этот контракт на имплементацию. Или передать только интерфейс еще незавершенной имплементации и коллега уже сможет начать писать свой код совместимый на уровне API с моим кодом. Конечно, это идеализированный мир, но смысл именно такой

Я хочу, что бы компилятор предупреждал меня и коллегу, о том, что контракт не соблюдается — типы не совпадают, кто-то не удосужился правильно подготовить данные, что является плохим звоночком.

Я понимаю о чем вы говорите, но хочу отметить что мы с вами решали бы одну и туже задачу по-разному, строили бы разную архитектуру и скорее всего использовали разные паттерны. И, думаю, в разных условиях наши стратегии были бы более или менее успешны. Что я хочу донести — тайпскрипт может быть эффективным в своем кругу задач, но не нужно его лепить просто так.

вступление про джс на 70% глупости
а так понимание места тайпскрипта правильное

Динамическая природа языка просто подталкивает к написанию универсальных функций, которые могут принимать десятки вариантов аргументов
динамическая природа освобождает от необходимости везде явно указывать типы, и решает в корне Dependency inversion которые нужен в языках как джава.
с отсутствием единого способа наследования объектов
он один, просто некоторые используют примеси и почемуто считают его наследованием
А еще, сама функция является объектом, в котором может быть неконтролируемое число методов и/или свойств.
тут у человека просто неприятие концепции функции как объекта, с таким же успехом можно сокрушатся как вообще у классов могут быть статические методы! что за бред!
моделью памяти JS,
такая же как и везде по сути, считает ссылки

вообщем много субъективного мнения основанного на не понимании концепций языка

Хорошо сказали. Вот только вырвали из контекста и не дочитали видимо.

Дочитал. Просто в основном часть негодования по поводу джс очень субъективна, но часть более чем имеет место быть.

с таким же успехом можно сокрушатся как вообще у классов могут быть статические методы! что за бред!
Не нужно сокрушаться. Статические поля и методы классов — весьма эпичный фейл с точки зрения правильного ООП, и, как известно, находятся в первой десятке косяков дизайна Java.

Замечательная статья для популяризации TypeScript, но только зачем нужно доказывать какие-то преимущества одного перед другим? Ведь этот подход элементарнейшим образом дискредитируется одним простым вопросом: на очень строго настрого типизируемом языке не пишут лапшекод?! С# и Java для джедаев?.. Это риторический, если что.
Для энтерпрайза главное — это стандарты и только стандарты. Если новый тимлид начнет тайпскрипт революцию там, где железно принято «аргумент ф-ции — объект, массив или строка», то весь проект откатится на пару месяцев назад на изучение, еще на пару на изобретение новых стандартов, а потом все время бороться с новичками (типизированным и крутыми), которые читали толстые книги по ООП.
TypeScript хорош? Хорош. Лучше JS? Не существенно.
У меня персонально к JS только две претензии: иногда, очень-очень редко, не хочется копипейстить, а прототипирование вызывает лимонный рефлекс; и многопоточность. Все остальные проблемы имхо от частой смены фреймворков.

не хочется копипейстить, а прототипирование вызывает лимонный рефлекс
не пробовали подключать ES6 ? или ФП использовать вместо ООП?

Підписатись на коментарі