Приветствую, коллеги! Вчера Microsoft напрягся и выкатил релиз следующей версии typescript, типизированной надстройки над javascript. В новой версии не только возведение в степень и раздельная конфигурация целей, но и первые наработки по async/await из стандарта ES7. Подробнее под катом.

async/await, но не для всех


Основная фича, долго обкатывавшаяся в бета версии — это поддержка ключевых слов async и await для работы с промисами на уровне языка. Этот синтаксис разрабатывается в рамках следующего стандарта ES7: одна из особенностей Typescript состоит в том, что он тащит языковые фичи не только из ES6, но и из ES7. К сожалению, текущая версия typescript может генерировать код async и await только для интерпретаторов js с поддержкой генераторов. Пока из таких node.js четвертой версии. Авторы обещают сделать поддержку для барузеров/ES5, но жалуются что такая реализация требует от кодогенератора создавать state machine, что сильно усложняет весь процесс компиляции.

"use strict";
// printDelayed is a 'Promise<void>'
async function printDelayed(elements: string[]) {
    for (const element of elements) {
        await delay(200);
        console.log(element);
    }
}
 
async function delay(milliseconds: number) {
    return new Promise<void>(resolve => {
        setTimeout(resolve, milliseconds);
    });
}
 
printDelayed(["Hello", "beautiful", "asynchronous", "world"]).then(() => {
    console.log();
    console.log("Printed every element!");
});


Полиморфный this


Теперь для возвращаемого значения функции можно указать this. Это значит — «объект этого класса или любого класса, наследованного от него». Очень удобно для создания «fluent api», когда метод возвращает объект заранее неизвестного типа:

interface Model {
    setupBase(): this;
}
 
interface AdvancedModel extends Model {
    setupAdvanced(): this;
}
 
declare function createModel(): AdvancedModel;
newModel = newModel.setupBase().setupAdvanced(); // fluent style works


--module теперь поддерживает ES6


Начиная с этой версии можно более гибко конфигурировать в какой javascript компилировать и для какой системы работы с модулями. Например, можно собрать ES6 код, но с commonjs модулями, для ноды:

//tsconfig.json targeting node.js v4 and beyond
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es6"
    }
}


ES7 возведение в степень


Небольшой синтаксический сахар из ES7, пришедший на замену Math.pow:

let squared = 2 ** 2;  // same as: 2 * 2
let cubed = 2 ** 3;  // same as: 2 * 2 * 2
let num = 2;
num **= 2; // same as: num = num * num;


Где брать?


Последняя версия typescript традиционно доступна на официальном сайте и в npm:

npm update typescript

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


  1. impwx
    01.12.2015 12:05
    +3

    Такая реализация требует от кодогенератора создавать state machine, что сильно усложняет весь процесс компиляции.

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


    1. a553
      01.12.2015 12:13
      +2

      Для TypeScript обычно новые фичи так и реализуются: сначала релиз с поддержкой только ES 6 как цели компиляции, а следующий релиз уже поддерживает перекомпиляцию в ES 5.


      1. impwx
        01.12.2015 13:10

        «Нормальную» поддержку async/await обещают только в 2.0, к сожалению — а его я бы раньше чем через год не ждал.


    1. ankh1989
      01.12.2015 13:31

      Не нужны там никакие стейт машины: гораздо лучше превращать всё в вызовы then. Пример уже есть: github.com/MatAtBread/nodent. Превращать async/await в конечный автомат — знатное извращение, но реализовать это проще если считать, что поддерживать yield всё равно надо (а тут уж без конечного автомата никак), а превращение async/await в yield — тривиальное. Вообщем типичный программёрский приём: сначала возьмём чайник с плиты и выльем воду (сведём задачу к уже решенной), после чего нальём воду обратно, вернём чайник на плиту и закипятим его (применим уже готовое решение).


      1. KReal
        01.12.2015 13:36

        Ну видимо хотят сделать как в дотнете, для единообразности)


      1. jakobz
        01.12.2015 21:05

        Мне кажется так не получится реализовать сложные случаи — типа try/catch, циклов с break/continue.


        1. ankh1989
          02.12.2015 07:11

          Выход из цикла можно сделать через бросание особого исключения. Насчёт сложных try..catch не знаю — не видел таких.


  1. Shablonarium
    01.12.2015 12:53
    +2

    Видел этот коммит по возведению в степень, не думал, что целиком заапрувят, по-моему конструкция num **= 2 — это уже перебор, это уже надругательство над иммутабельностью.

    Таким образом для единообразности тогда надо и тригонометрические функции добавить, например, вычисление синуса будет делаться вот так:
    num Sin=


    1. a553
      01.12.2015 13:20

      Вот тоже не понимаю зачем это в ES внесли.


      1. ankh1989
        01.12.2015 13:32
        +1

        Потому что уже есть +=, -=, *=, /= и т.д.


        1. impwx
          01.12.2015 13:38

          Было бы очень актуально также получить ||=, например для присвоения значений по умолчанию.


        1. a553
          01.12.2015 15:39

          Я имею ввиду оператор ** вообще, а не **= отдельно.


    1. hell0w0rd
      02.12.2015 00:36
      +1

      а при чем тут иммутабельность?


  1. aylarov
    01.12.2015 17:55
    +1

    Приятно видеть, что TypeScript тоже не стоит на месте, будем использовать async / await теперь


    1. hell0w0rd
      02.12.2015 00:37
      +1

      Скажите, а можно подменять рантайм async/await?
      В babel можно async-to-generator, там встроенная функция, а можно в bluebird.coroutine, которая сейчас самая быстрая.
      PS вопрос не к aylarov, а в основную ветку.


      1. vindi
        02.12.2015 08:58

        Как я написал в посте, сейчас async/await реализуется строго через ES6 генераторы. Можно использовать babel для последующей генерации ES5 с нужным рантаймом. Или подождать версии 2.0, где обещают async/await для ES5 — возможно там будет возможность выбора рантайма. А возможно и не будет — трудно предсказывать будущее :)


        1. hell0w0rd
          02.12.2015 09:14

          Не, вы меня не поняли. У async/await в ES6 толжен быть враппер/бэкенд/рантайм, как хотите называйте.
          На выходе код выглядит как-то так:

          asyncToGenerator(function *() {
            yield something();
          });
          

          Вот мой вопрос прост — можно ли подменить функцию asyncToGenerator на нужную мне. Я просто пока не использую TS, не знаю какие возможности настраивать компилятор, но хочу начать, потому спрашиваю.