Компания Microsoft активно выпускает новые версии TypeScript. Товарищи разработчики объявили о выпуске бета версии TS версии 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. Он для энтерпрайза больше подходит. Но это мое имхо, так что на вкус и цвет.
