Релиз TypeScript 1.6: не только React

0257038c07224fe4b32f552f9d14a6a8.pngКомпания Microsoft активно выпускает новые версии своего диалекта JavaScript. Товарищи разработчики объявили о выпуске бета версии TypeScript версии 1.6 аж второго сентября. А уже 16 сентября был выпущен релиз. Скоростные ребята. Но при этом релиз как-то прошел незамеченным (не для всех, но все же). На Хабре как-то не было упоминаний (я не нашел). А посему немного информации по улучшениям.

Одна из мощных фич этой версии заключается в нативной поддержке синтаксиса React/JSX. Но это не все. Вот перечень некоторых нововведений:

  • Генераторы ES6
  • Локальные типы
  • Алиасы на генерик типы
  • Классовые выражения (анонимные классы)
  • Поддержка JSX
  • Абстрактные классы и методы
  • Новый флаг –init
  • Новая секция “exclude” в конфигурационном файле tsconfig.json


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

Генераторы ES6


Тут все просто – можно теперь писать функции генераторы. Их можно типизировать, естественно. Интерфейс генератора выглядит так:

interface Generator<TYield, TReturn, TNext> extends IterableIterator<TYield /*| TReturn*/> {
    next(n: TNext): IteratorResult<TYield /*|TReturn*/>;
    // throw and return methods elided
}


Пример использования:


interface Generator<TYield, TReturn, TNext> extends IterableIterator<TYield | TReturn> {
   next(n: TNext): IteratorResult<TYield | TReturn>;
}


function *g(): Generator<number, any, string> {
   let x = yield 0; // x имеет тип string
}



Больше примеров можно найти по ссылке github.com/Microsoft/TypeScript/issues/2873

Локальные типы


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


function f() {
   if (true) {
      interface T { x: number }
      let v: T;
      v.x = 5;
   }
   else {
      interface T { x: string }
      let v: T;
      v.x = "hello";
   }
}
 


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


function f() {
   enum E {
      A, B, C
   }
   class C {
      x: E;
   }
   interface I {
      x: E;
   }
   type A = I[];
   let a: A = [new C()];
   a[0].x = E.B;
}



Больше примеров можно найти по ссылке github.com/Microsoft/TypeScript/pull/3266

Алиасы для генериков


Новая возможность позволяет задавать псевдонимы на генерики. Пример кода:


type Source<T> = T | (() => T);

function unwrap<T>(p: Source<T>) {
   return (typeof p === "function") ? p() : p;
}


Больше примеров можно найти по ссылке github.com/Microsoft/TypeScript/issues/1616

Class expressions


У нас всегда была возможность объявлять классы. Теперь есть возможность описывать классовые выражения. Такие выражения представляют из себя анонимные классы, по аналогии с анонимными функциями. Пример кода:


var Rect = class {
   area: number;

   constructor(public length: number, public width: number) {
      this.area = this.length * this.width;
   }
}

var rect = new Rect(5, 10);

var MyNode = class Node {
   next: Node;
   set nextNode(node: Node) {
      this.next = node;
   }
   constructor() {}
}

var node = new MyNode();
var nextNode = new MyNode();
node.nextNode = nextNode;



Абстрактные классы


Тут все просто. У нас появилось ключевое слово abstract, которое, как и в других языках программирования, ставится перед определением класса и/или метода. В итоге мы можем объявить класс с реализацией, но от него нельзя создавать экзмепляры объектов.


type int = number;

abstract class A {
   foo(): int { return bar(); }
   abstract bar() : int;
}

class B extends A {
   bar() {
      return 42;
   }
}

new A(); // Error!
new B(); // OK



User defined type guard functions


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

function isCat(a: Animal): a is Cat {
   return a.name === 'kitty';
}

var x: Animal;

if(isCat(x)) {
   x.meow(); // OK, x is Cat in this block
}



React/JSX = TSX


В компиялторе появилась новая опция --jsx react. Если она указана, то происходит транспилирование JSX синтаксиса прямо в TS файлах. Точнее даже TSX (по аналогии с JSX). Пример такого кода:


export interface ITodoItemState {}

export interface ITodoItemProps {
   item: ITodo;
   onRemove?: (todo: ITodo) => any;
   key?: number;
}

export class TodoItem extends React.Component<ITodoItemProps, ITodoItemState> {
   constructor () {
      super();
      this.removeItem = this.removeItem.bind(this);
   }

   removeItem () {
      this.props.onRemove(this.props.item);
   }

   render () {
      return (
         <li>
            <span> {this.props.item.description} </span>
               <button onClick={this.removeItem} >delete</button>
         </li>
      );
   }
}



До сегодняшнего дня, чтобы разрабатывать на React+TypeScript, приходилось использовать либо React templates (что мы и делаем в Tutu.ru), либо вовсе отказаться от JSX синтаксиса. Но теперь у нас появляется возможность использования JSX, что называется, из коробки. Любителям React это должно понравиться.

Есть два режима работы:

  • --jsx preserve — на выходе получаем JSX
  • --jsx react — на выходе получаем обработанный JS


А вообще получилась хорошая альтернатива бабелю. Я бы даже сказал что конкуренция (в некоторых вещах). Если вы используете BabelJS + Flow, то посмотрите на TS. Он для энтерпрайза больше подходит. Но это мое имхо, так что на вкус и цвет.

© Habrahabr.ru