Здравствуйте, меня зовут Александр Черников. Я руковожу разработкой UI проекта “Цифровой корпоративный банк” — обновлённой версии Сбербанк Бизнес Онлайн, интернет-банка для юридических лиц. Мы разрабатываем stand-alone клиент, мобильное приложение и, собственно, web-клиент, о котором и пойдёт речь. В своих статьях я буду делиться ценным опытом нашей команды, а конкретно в этом посте опишу наш технологический стек и остановлюсь на том, почему мы выбрали Typescript в качестве основного языка.




Новую версию Сбербанк Бизнес Онлайн мы пишем 2,5 года. Уже в следующем году мы планируем перевести на него всех корпоративных клиентов Сбербанка.

Итак, начнем со стека. Мы внедрили TypeScript, React, Reflux(legacy), Redux, Bluebird Promise и Bootstrap. Стили пишем на LESS. Все это добро мы собираем с помощью Babel, Webpack и его плагинов. Webpack пока первой версии, но собираемся перейти на вторую. Многие могут спросить: зачем нам Typescript и Babel одновременно? Во-первых, раньше TypeScript не все умел транспилировать, и только недавно сравнялся с Babel по этой функциональности. Во-вторых, TypeScript не умеет кэшировать. А babel умеет хранить готовые ES5 скрипты в папке. Если исходники не поменялись, он сразу берет их оттуда. Когда проект собирается несколько минут, такая экономия времени очень радует.

Стек технологий достаточно свежий. Ребятам приходится вникать сразу в несколько вещей: например, в TS, React, Redux, в сам проект и в термины нашего банка. Из 50-60 человек только 20 процентов работают в штате, остальные подключаются от вендоров и часто меняются.

Как мы справляемся в таких условиях с code-review? Раньше несколько самых опытных разработчиков смотрели код всех команд, была такая небольшая пирамида. Сейчас мы стараемся равномерно распределить по командам. Во многих командах появились так называемые эксперты (хорошо разбираются в проекте, знают, что и где лежит), чтобы не изобретали велосипеды и прочее. Соответственно они review’ят не только ребят из своей команды, но и из других.

Review у нас немного автоматизировано и на pull-request у нас добавляются лейблы, которым нужно соответствовать. Тогда они станут зелеными и ПР автоматически сольется. Лейблы есть разные: Code-style, Expert, Architect, CSS, E2E-test и другие. Если меняются .less файлы — добавляется CSS, если меняется какой-то код ядра или низкоуровневых вещей — добавляется Architect. Чтобы получить Expert, нужно набрать как минимум 2 аппрува экспертов.
И если человек новенький на проекте или не очень силен в JS, тогда его код будет сильно отличаться от того, что было до code-review.

TypeScript и JavaScript


Я застал тот момент, когда многие писали на TS и использовали новые фичи, которые транспилируются в ES5. Но даже тогда мы использовали TS для типизации, для некоего статического анализа кода на ошибки. Да, на JS можно написать код грамотно и правильно, но он тебя не подстрахует так, как TS. Кто-то ставит в минусы, что приходится много писать TS-кода (overhead), т.е. типизация, типы, интерфейсы и др. Когда мы рефакторили “старый” код JS > TS, то выявлялись элементарные ошибки, которые сработают только в runtime. То запятая не там стоит, то точку забыли, то скобки рано закрыли и т.д., не говоря уже про недосягаемый код и неиспользуемые аргументы и пр… Когда система большая и команда не может покрыть всю систему тестами, то TS спасает. При 3000-4000 скриптах вообще трудно представить, как жить без TS.

Конечно, когда мы пишем код на JavaScript, то можем помочь компилятору и писать код, словно у нас типизированный язык: не переопределять переменные, не записывать в них разные типы, возвращать всегда один и тот же тип. Возникает вопрос: если при этом использовать babel.js, есть ли в таком случае смысл в изучении TypeScript?

Мы часто спорим по этому поводу. Некоторые коллеги говорят: “А зачем нам TS? Мы пишем код грамотно и проводим тщательно code-review, отбираем людей на собеседовании, да и вообще джедаи JS”. Но ведь человеческие факторы никто не отменял: лень, торопливость, невнимательность. Ничего не мешает подключить TS к вашему JS-коду. Если у вас действительно нет ни одной ошибки, то компилятор ничего не найдет — можете радоваться тому, что у вас отличная команда, и звезды сложились как надо. Но перестраховаться с помощью TS все равно не мешает. Тем более, что и особых затрат это не потребует.

К тому же, в этом году в версии 1.8 в TS сделали удобную фичу. Теперь можно проверить типы в чистом JS — достаточно добавить файлы “.js” в проект и allowJs флаг. Если есть какой-то код, который не хотите проверять, то спокойно его можно игнорировать через аннотацию @ts-nocheck. Во время code-review мелкие баги отловить почти нереально, а TS помогает экономить силы и время. А не то подольешь релизную ветку в develop с конфликтами в 100 файлах… хотел бы я посмотреть, как человек хладнокровно нажмет кнопку MERGE.

TypeScript vs Flow


“А как насчет Flow?” — спросите вы. Мы выбирали между ES6 и Typescript, про Flow тогда никто не знал. Для тех кому интересно, в чем разница их статического анализа кода, могу посоветовать интересный доклад Ильи Климова с конференции HolyJS 2017 Piter, где он сравнивает TypeScript и Flow.

Ложки дегтя


Помимо overhead у Typescript есть еще несколько недостатков:

  1. Существенное замедление сборки проекта. Но это, опять же, исключительно в нашей специфике сборки: Webpack + TS + Babel. У кого такая же конфигурация (+- babel), могу посоветовать использовать загрузчик ts-loader обязательно с флагом transpileOnly, а TSC запускать параллельно. А в режиме инкрементальной сборки (--watch), держать 2 процесса отдельно: webpack --watch и tsc --watch.
  2. Возникают проблемы с OutOfMemory ошибками nodeJS, особенно неприятны такие сюрпризы, когда нужно собрать проект и выпустить релиз через 3-4 дня, а быстро решить их не получается.
  3. Необходимость актуализации версий .d.ts для внешних библиотек. Слава Богу, закончилась пора с tsd > typings. И теперь все можно качать сразу через npm > @types. А что если вышла новая версия библиотеки, lodash например, а .d.ts еще нет? Тогда приходится выбирать: дописать самому (в репозиторий или выложить ПР на github в репозиторий DefinitelyTyped) или пока не использовать эту фичу.
  4. Поиск разработчиков с опытом на TypeScript. Это отдельные слезы нашего HR. Насколько мне известно, на рынке у всех сейчас проблема с поиском “продвинутых” frontend-разработчиков с опытом написания серьезных SPA, Angular | React | Vue, Typescript, Redux и пр.

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


  1. megaboich
    30.10.2017 16:40
    +2

    В целом поддерживаю, только Babel на мой взгляд уже давно не нужен.


    Webpack пока первой версии, но собираемся перейти на вторую.

    Уже версия 3 давно.


    TypeScript не умеет кэшировать. А babel умеет хранить готовые ES5 скрипты в папке.

    Awesome-typescript-loader. Он умеет кешировать и компилить асинхронно


    1. redyuf
      30.10.2017 16:53
      -1

      В целом поддерживаю, только Babel на мой взгляд уже давно не нужен
      А как же гибкость? У бабела хорошая база transformation плагинов и их апи пока лучше, чем в ts.

      В 7м бабеле (пока еще бета) запилили поддержку синтаксиса typescript: babel-preset-typescript. Так что можно сказать, что и ts для целей сборки не нужен.

      Интересно, что будет, если в flow запилят поддержку ts и плагинов для Language Service API?


    1. 96467840
      30.10.2017 17:12

      у нас как раз с ним (awesome-typescript-loader) вышла трабла: куча ошибок Duplicate identifier '...'. и пришлось вернутся на ts-loader

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


      1. DarthVictor
        31.10.2017 10:10

        у нас как раз с ним (awesome-typescript-loader) вышла трабла: куча ошибок Duplicate identifier '...'. и пришлось вернутся на ts-loader

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

        Нет, github.com/s-panferov/awesome-typescript-loader/issues/135


    1. alerkesi
      30.10.2017 18:27

      Да, мы в курсе про вторую :) думаю, там с переходом небольшая разница.
      Пробовали atl — не увидели роста производительнсти. В любом случае проверку типов мы в тот же процесс сборки не вернем — это все равно затратно.


    1. xadd
      30.10.2017 20:25

      TS -> EsNext -> Babel — лучший вариант — поддержка плагинов + конфигурируемая транспиляция


  1. MonkAlex
    30.10.2017 17:04

    Очень сложно вас воспринимать всерьез, когда прод иногда показывает большие белые страницы без контента, а прямо сейчас например в логе (не банка, сайта), куча вот такого:

    Заголовок спойлера
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] ManageableArea.css
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] template.js
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] template.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] ManageableArea.js
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] template.js
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] template.js
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] template.js
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] template.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] targetingContainer.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] aurora.containers.js
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:81196
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:112675
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:113265
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:129537
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:132732
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:134699
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:147881
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:147971
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:149320
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:229550
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:253789
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:264000
    unreachable code after return statement[Подробнее] portallibs-core.min.js:54:266888
    unreachable code after return statement[Подробнее] portallibs-core.min.js:73:2434
    window.controllers/Controllers является устаревшим. Не используйте его для определения UA. portallibs-core.min.js:54:25181
    Синхронный XMLHttpRequest в основном потоке является устаревшим из-за его пагубного влияния на работу конечного пользователя. Для получения дополнительной помощи обратитесь к xhr.spec.whatwg.org portallibs-core.min.js:2:81642
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] loader_bundle.min.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] header.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] sbt.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] atc-libs.min.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] Breadcrumb.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] push-notifications.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] common.maven.min.js
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] SBO.svg
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] content
    Public-Key-Pins: Сайт указал заголовок, в который не был включён подходящий pin.[Подробнее] identifier
    Public-Key-Pins: Сайт указал заголовок, который не удалось успешно распарсить.[Подробнее] shared.css
    Загрузка


    1. alerkesi
      30.10.2017 18:17

      Вы показываете что-то странное, уверены что это с сбербанк бизнес онлайн? Поверьте мне, если у нас на каких-то страницах просто белый экран — мы уже про это знаем и скорее всего это уже починено ;)


    1. alerkesi
      30.10.2017 18:18

      Возможно один из ваших плагинов в браузере что-то ругается.


    1. SkyWar
      31.10.2017 19:24
      -1

      VM346:2 Refused to connect to 'https://127.0.0.1/' because it violates the following Content Security Policy directive: «connect-src 'self' bf.sberbank.ru:9443 *.group-ib.ru sbrf.livetex.ru www.google-analytics.com nlb-efsd1.sbrf.ru:444».

      f.pb @ VM346:2
      (anonymous) @ VM346:2
      check @ VM346:2
      (anonymous) @ VM346:2
      setTimeout (async)
      start @ VM346:2
      f.K @ VM346:2
      start @ VM346:2
      d.tf @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      setInterval (async)
      a @ VM346:2
      f.Vd @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM345:1
      (anonymous) @ VM345:1
      x.onreadystatechange @ grlb.js?ver=27hf.001.00:18
      XMLHttpRequest.send (async)
      cb @ grlb.js?ver=27hf.001.00:18
      VM346:2 Refused to connect to 'https://127.0.0.1:80/' because it violates the following Content Security Policy directive: «connect-src 'self' bf.sberbank.ru:9443 *.group-ib.ru sbrf.livetex.ru www.google-analytics.com nlb-efsd1.sbrf.ru:444».

      f.pb @ VM346:2
      (anonymous) @ VM346:2
      check @ VM346:2
      (anonymous) @ VM346:2
      setTimeout (async)
      start @ VM346:2
      f.K @ VM346:2
      start @ VM346:2
      d.tf @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      setInterval (async)
      a @ VM346:2
      f.Vd @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM345:1
      (anonymous) @ VM345:1
      x.onreadystatechange @ grlb.js?ver=27hf.001.00:18
      XMLHttpRequest.send (async)
      cb @ grlb.js?ver=27hf.001.00:18
      VM346:2 Refused to connect to 'https://127.0.0.1:22/' because it violates the following Content Security Policy directive: «connect-src 'self' bf.sberbank.ru:9443 *.group-ib.ru sbrf.livetex.ru www.google-analytics.com nlb-efsd1.sbrf.ru:444».

      f.pb @ VM346:2
      (anonymous) @ VM346:2
      check @ VM346:2
      (anonymous) @ VM346:2
      setTimeout (async)
      start @ VM346:2
      f.K @ VM346:2
      start @ VM346:2
      d.tf @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      setInterval (async)
      a @ VM346:2
      f.Vd @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM345:1
      (anonymous) @ VM345:1
      x.onreadystatechange @ grlb.js?ver=27hf.001.00:18
      XMLHttpRequest.send (async)
      cb @ grlb.js?ver=27hf.001.00:18
      VM346:2 Refused to connect to 'https://127.0.0.1:445/' because it violates the following Content Security Policy directive: «connect-src 'self' bf.sberbank.ru:9443 *.group-ib.ru sbrf.livetex.ru www.google-analytics.com nlb-efsd1.sbrf.ru:444».

      f.pb @ VM346:2
      (anonymous) @ VM346:2
      check @ VM346:2
      (anonymous) @ VM346:2
      setTimeout (async)
      start @ VM346:2
      f.K @ VM346:2
      start @ VM346:2
      d.tf @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      setInterval (async)
      a @ VM346:2
      f.Vd @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM346:2
      (anonymous) @ VM345:1
      (anonymous) @ VM345:1
      x.onreadystatechange @ grlb.js?ver=27hf.001.00:18
      XMLHttpRequest.send (async)
      cb @ grlb.js?ver=27hf.001.00:18
      VM346:2 Refused to connect to 'https://127.0.0.1:5985/' because it violates the following Content Security Policy directive: «connect-src 'self' bf.sberbank.ru:9443 *.group-ib.ru sbrf.livetex.ru www.google-analytics.com nlb-efsd1.sbrf.ru:444».


  1. Juma
    30.10.2017 17:50

    4. Поиск разработчиков с опытом на TypeScript. Это отдельные слезы нашего HR
    Я вас правильно понимаю, что вы ищете именно TypeScript разработчиков, не JS (остальной набор технологий достаточно популярный). Конечно JS и TS различаются, кроме типов еще различия в классах и т.п. Но все же много общего. Да и TS в итоге транслируется в JS.


    1. alerkesi
      30.10.2017 18:22
      +1

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


      1. ivanovSP
        31.10.2017 13:26

        кто дальше песочницы с ним работал — не так много.

        Это вы про 18 летних студентов за 50 000 рублей?

        200 000 рублей и такой специалист у вас в кармане


        1. alek0585
          31.10.2017 23:48

          А за 250 не только в кармане да?


          1. ivanovSP
            02.11.2017 00:25

            оооо) за 250 000 на галере будет примерно такие слова от директора: «Что, 250? больше чем у меня? Да кто он такой, там же всего лишь кнопку подсвечивать нужно через CSS, это же верстка, я в 1990 года сам такое делал на таблицах!!»

            Специалистов полно, только они не готовы работать за вшивые 120 000 рублей. (если кто-то читает эту строку и недоумевает, поздравляю, тебе сбили самооценку и ты поддался под влияние работодателя, перейди по двум ссылкам ниже что бы восстановить свой разум)

            labor-union.wikia.com/wiki/Main
            labor-union.wikia.com/wiki/Lifehacks
            (СОВЕТУЮ ВСЕМ ПОЧИТАТЬ)


        1. alerkesi
          01.11.2017 03:18

          Ну вы знаете, месяц собеседований по 3 в день и да, 1 у вас в кармане:) А когда вам надо вывести хотя бы 6-7 человек за месяц?
          А про студентов, скорее так: 25 летние новоиспеченные jsники после курсов, пару песочниц и они уже хотят далеко не 50.


          1. ivanovSP
            02.11.2017 00:13

            Дефицита нет, а есть избыток. Достаточно зайти на LinkedIn, поискать анкеты людей и убедиться, что на территории РФ существует избыток квалифицированных кадров с обширными и углубленными знаниями и уклоном в различные специализации. При этом российские бизнесмены и «красные директора» любят распространять тлетворный миф о наличии на российском рынке труда дефицита кадров, согласных работать у них на проектах, и при этом забывают добавлять: "… за еду". Суть всех этих сказок про дефицит специалистов сводится к следующему. Бизнесмен или «красный директор» имеет в штате 50 инженеров, которым он суммарно платит в год 25 миллионов рублей. Он хочет начать тратить в год 20 миллионов рублей вместо 25 миллионов, продолжая иметь в штате то же самое количество специалистов, способных совершать в год то же самое количество человеко-часов труда. Поэтому бизнесмен хочет, чтобы количество инженеров на рынке удвоилось или утроилось, чтобы можно было резко понизить з/п текущим инженерам в штате, а на место уходящих инженеров всегда иметь возможность найти новых по еще более дешевой цене. Нередко бизнесмены и сами занимаются организацией курсов при вузах или заставляют своих лучших технических специалистов учить студентов или интенсивно доучивать выпускников с целью помочь бизнесмену раз и навсегда обвалить рынок труда. Многие старшие инженеры хорошо разбираются в своих областях, но обладают экономической безграмотностью, не читали Карла Маркса и не понимают, что они готовят для своего начальника промышленную резервную армию труда.

            На все речи бизнесменов, рассказывающих о нехватке специалистов на российском рынке труда, нужно отвечать так: «С чего вы взяли, что в РФ есть нехватка квалифицированных кадров? Кто мешает лично вам зайти на LinkedIn и сегодня же найти на едином глобальном рынке труда русскоговорящих квалифицированных специалистов для вашего бизнеса, переманив их с других проектов? Если вам не хватает денег, то это ваши проблемы. Бизнесмену никто ничего не обещал. Ему некто не обещал, что его бизнес будет рентабельным. Вы — лузер, и ваш бизнес не имеет права на существование, потому что вы не вписались в рынок»


    1. search
      31.10.2017 10:29

      У меня такая же реакция была. 2 дня, ну максимум неделя понадобится программисту чтоб освоиться с ТС. Это если он ну совсем никогда не сталкивался со строго-типизированными языками. Да, придется разобраться с дженериками и смириться с тем, что ты не можешь передавать и возвращать всё что угодно куда угодно (что в итоге пойдёт только на пользу). Причем писать и понимать код программист начнёт сразу, а не через 2 дня.


      1. knotri
        31.10.2017 15:47

        Ой не скажите.
        Когда в аргумент передается функция все становится тяжело
        const negate = (fn: Function) => (...args: any[]) => !fn(...args)
        Или когда пробуешь описать React типы.
        Дженерики говорите простые?
        Вот я писал


        export const mapReplace = <A extends {}, U extends {}>(
          array: A[],
          test: (item: A) => boolean,
          replacement: (item: A) => U
        ): (A | U)[] => {
          return array.map((item: A) => {
            return test(item) ? replacement(item) : item
          })
        }

        И как вам такое? Сходу понятное?


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


        <T>size(objectOf<T>) => number 

        это не правильный генерик. Должно быть any вместо T


        1. mayorovp
          31.10.2017 17:07

          Что-то вы сами себе все усложнили.


          export function mapReplace<A,U>(
            array: A[],
            test: (item: A) => boolean,
            replacement: (item: A) => U
          ): (A | U)[] {
              return array.map(item => test(item) ? replacement(item) : item);
          }

          Нормально пишется и читается.


          1. knotri
            31.10.2017 17:43

            Без


            mapReplace = <A extends {}, U extends {}>

            не заработает из-за конфликта с jsx (хотя я сейчас проверил — у меня заработало, магия какая-то)
            https://stackoverflow.com/questions/32696475/typescript-tsx-and-generic-parameters


            Ну а функцию да, можно в одну строку записать


            1. mayorovp
              31.10.2017 19:28

              Два параметра уже не удовлетворяют синтаксису tsx, а потому их можно использовать без проблем.

              Кроме того, ключевое слово function также исключает понимание угловых скобок как тэга.


            1. Druu
              01.11.2017 03:31

              > не заработает из-за конфликта с jsx

              Так это проблема jsx. TS тут при чем?


              1. knotri
                02.11.2017 11:23

                jsx+TS = tsx в котором и не работает


        1. TheShock
          01.11.2017 04:08

          Когда в аргумент передается функция все становится тяжело

          Ну что вы хотите, писать на «фп» и чтобы у вас из ноги кровь не текла? Тут или одно или другое

          И как вам такое? Сходу понятное?

          Мне меньше всего понятен смысл этого: (A | U)[]. Зачем массив с двумя разными типами? Как с ними работать вообще? То есть вот у вас есть A[], с ним понятно как работать, а потом, после этой функции в этом массиве начинает попадаться то A, то U. А потом как? if (x instanceof U) ? Код, конечно, не самый изящный, но проблема скорее в архитектуре.

          Плюс еще названия. A и U — просто рандомные буквы? Вот так было бы значительно понятнее:
          export function mapReplace<TCurrent, TReplace>(
            array: TCurrent[],
            test: (item: TCurrent) => boolean,
            replacement: (item: TCurrent) => TReplace
          ): (TCurrent | TReplace)[] {
              return array.map(item => test(item) ? replacement(item) : item);
          }


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

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


  1. vasIvas
    30.10.2017 18:26
    -1

    Все описанное в статье является устаревшим, как минимум на год и самое главное что не указаны сильные и слабые стороны, как было заявлено в заголовке. Хорош — система типов с продвинутым выводом типов, учит писать правильный код. Плох — когда разработчики начинают писать :type, они уже себя считают typescript разработчиками (особенно это касается js dev only) и мне кажется что 99% разработчиков не понимают с чем они работают на самом деле. TypeScript это не java и не c#. TypeScript, это типизация следующего поколения. Кроме того, не сложно описать типы для кода, сложно описать типы для библиотек. один раз было что пол дня не мог тип описать.


    1. vasIvas
      30.10.2017 18:34

      И ts сравнивать с flow не корректно, так как у них разные виды типизации. То есть, они различаются как яблоко и iphone.


      1. varanio
        30.10.2017 18:55
        +1

        Объясните плиз на пальцах, в чем разница


        1. wert_lex
          31.10.2017 12:02

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


          Собственно, на первый взгляд flow и ts про одно и то же. Если немного приглядеться, то flow всё же больше про js + types и система типов более правильная. Зато у ts сильно лучше туллинг и сильно больше библиотек уже искоробки. Потому ts всех и победил. Хотя, как по мне, flow интереснее.


      1. x512
        30.10.2017 20:54

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


    1. haiflive
      31.10.2017 08:11

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

      а TypeScript, да, я считаю это прорыв, очень удобный и выразительный язык, особенно после js


    1. RyDmi
      31.10.2017 10:43

      TypeScript, это типизация следующего поколения

      А можно поподробнее? Очень любопытно.


  1. search
    31.10.2017 10:43

    Радует, что две из четырёх описанных болячки вылечили еще в прошлом году.
    Интересно, а есть ли статьи, описывающие негативный опыт внедрения TS? У меня лично от него позитивные впечатления, не понимаю почему многие его боятся.


    1. psFitz
      31.10.2017 11:35

      Бесятся потому-что надо учить новый язык, а это "сложно и долго"


  1. Desire2304
    31.10.2017 10:44

    У нас в компании все перешли на TypeScript. Все довольны.


  1. constantant
    31.10.2017 10:44

    Ребятам приходится вникать сразу в несколько вещей: например, в TS, React, Redux, в сам проект и в термины нашего банка.

    Но честно говоря, у них есть на это время, пока получают доступ к системе испытательный срок закончится ;)

    Да, на JS можно написать код грамотно и правильно, но он тебя не подстрахует так, как TS.

    А в случае с Eclipse это невозможно вообще, только не говорите, что вам таки купили WebStorm??? )))

    Необходимость актуализации версий .d.ts для внешних библиотек. Слава Богу, закончилась пора с tsd > typings. И теперь все можно качать сразу через npm > @types.

    И не мешает отсутствие интернета? Nexus разве уже поддерживает @группы?


    1. alerkesi
      01.11.2017 03:11

      1) У новеньких есть на это время, мы же не заваливаем их сразу багами или доработками. И учетки и доступ даются быстрее, чем 3 месяца;) возможно вам не повезло с проектом и ответственными.
      2) У нас круче — Idea.
      3) У нас nexus поддерживает @subfolder и есть интернет. В двух словах: когда общий нексус СБТ не поддерживал, суперадмины нашего проекта подняли свой (новой версии) специально для нас, а позже мы вернулись в общий. Все решается, было бы желание!


      1. constantant
        01.11.2017 14:04

        1) HRы будут довольны таким ответом
        2) Про «круче» — холивар, но не в этом дело. Idea тоже денег стоит, значит на воровонной сидите или с личными лицензиями, что по внутренним порядкам запрещено.
        3) Привет Anykeyеву


  1. gadfi
    31.10.2017 11:15

    а можно какие то кейсы где ts лучше js?
    не халивара ради, в мир js я пришел из java — привык к строго типизированным языкам, но учитывая весь сахар es6/es7 у меня еще не было ни разу ситуации в которой мне реально не хватало бы типизации в js
    В разрезе react мне за глаза хватает типов в PropTypes
    я не против ts но вопрос зачем остается открытым, хотелось бы какого то реального сравнения такой то кейс на js пишется за столько то на ts за столько, есть риск вот таких багов и экономия в будущем такая


    1. search
      31.10.2017 11:43

      Из очевидных:


      1. Code completion как у взрослых языков (новому программисту гораздо проще понять код)
      2. Видишь все ошибки при рефакторинге. Мы как-то переносили проект с angular 1 на angular 2, так у меня после переноса и изменения (допила-перепила) нескольких десятков файлов всё заводилось с первого раза. За годы работы со сквозной типизацией такое воспринимается как чудо
      3. Застрахован от очень многих ошибок рантайма. Тот же PropTypes покажет вам ошибку только когда она уже случилась (поправьте если это не так). Как говорится, со строгой типизацией сложнее по случайности отстрелить себе ногу. Например, при использовании Promise.all вы получаете массив значений в результат. И вот тут очень легко всё зафакапить, по ошибке указав не тот индекс. Тайпскрипт такого не допустит.


      1. gadfi
        31.10.2017 12:16

        1, 2 во многом решает webstorm, 3 не совсем корректно PropTypes проверка работает только в dev, но если вы что то сделали не так то оно и не заведется
        с промисами согласен, но пока особенно не мешало


        1. some_x
          31.10.2017 12:58

          1, 2 во многом решает webstorm


          Да не возможно это так же качественно сделать как в ts.


        1. search
          31.10.2017 13:08

          Еще такой момент. Обычно, при устройстве на работу, в контракте есть пункт, о том, что девелопер обязуется предоставить лучшие практики разработки доступные на текущий момент. Понятно что этот пункт весьма спорный и чаще всего трудновыполнимый. Но в неиспользовании тайпскрипта по причине "нам и без него хорошо" (других причин я натурально не способен придумать) видится банальное нарушение условий контракта. Такие дела.


          1. gadfi
            31.10.2017 14:32

            я пишу не только react.js но и react native, хоть пример mayorovp выглядит очень разумно, но до версии rn 1.0 ts точно использовать не буду ) а вот для react.js нужно будет попробовать


        1. mayorovp
          31.10.2017 13:23

          Знает ли webstorm что когда вы пишите, условно, foo.addEventListener("bar", e => e.|); какие будут свойства у параметра e? А если знает, то что делать с более сложным случаем?


          mobx.observe(foo, e => {
              if (e.type == "update") {
                   e. // 1
              }
              if (e.type == "splice") {
                   e. // 2
              }
          });

          Знает ли webstorm что в точках (1) и (2) будут разные списки доступных свойств?


          1. gadfi
            31.10.2017 14:24

            спасибо, подобных примеров я и ждал


          1. cccco
            31.10.2017 19:23

            Можно для более строгой типизации ещё немного доработать:

            mobx.observe(foo, e => {
                if (e.type == "update") {
                     (e as update). // 1
                     // Либо
                    (<update>e). // 1
                }
                if (e.type == "splice") {
                     (e as splice). // 2
                     // Либо
                    (<splice>e). // 2
                }
            });

            Понятно, что для JSX подходит только первый вариант, т.е. as-синтаксис.


            1. mayorovp
              31.10.2017 19:30

              Но зачем писать лишний код когда компилятор и так все понимает?! Кстати, не update и splice — а IArrayChange<T> и ArraySplice<T>, причем тип T еще нужно где-то найти...


              1. cccco
                01.11.2017 20:43

                Да, согласен, написал не в тему, поспешил (людей насмешил).
                Не разглядел mobx, т.к. с mobx не пересекался. Подумал, что в свойстве e.type хранится тип самого объекта e, т.е. update и splice — суть возможные типы объекта e. Соответственно, конструкции: (e as update). и (e as splice). помогут webstorm знать в точках (1) и (2) списки доступных свойств.


        1. TheShock
          01.11.2017 04:13

          3 не совсем корректно PropTypes проверка работает только в dev

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


    1. knotri
      31.10.2017 15:52

      Как минимум это спасает от опечаток — в js (с бабел и вебпак) код скопмилится и сломается в рантайме — с typescript-ом просто не скомпилиться


  1. mSnus
    31.10.2017 11:35

    В общем, TS хорош тем, что он новый. И плох тем же.


    1. search
      31.10.2017 13:46

      Месяц назад день рождения праздновал. 5 лет. По меркам фронтенда это долгожитель.


  1. x07
    31.10.2017 21:00

    А пробовали обновлять инструменты, которые используете, проект стартует? Не задумывались о том, что когда придет время переходить на более свежие версии, то придется много чего переписать, выкинуть и перенастроить окружение полностью?


    1. alerkesi
      01.11.2017 03:26

      Конечно задумывались, и обновляли, и страдали и иногда дорого.
      Иногда даже не обновляешь версии, а в пн бах — и уже не собирается, потому что где-то косвенная зависимость нестрого: ^0.1.1 версию тянет и все, как было недавно с babel-transform-generator (если не изменяет память). Npm-Shrinkwrap нас спасет!


      1. x07
        01.11.2017 09:28

        А вы собираетесь обновлять окружение? Или этот проект отработает отведенное ему время, а потом просто перепишите все с нуля?