czwartek, 20 czerwca 2013

TypeScript 0.9 (2)

Dziś podsumuję najbardziej istotne zmiany w nowym TypeScript 0.9. Następnym razem podzielę się wnioskami z nowej specyfikacji i praktycznymi działaniami.

 

Generyki

Wiele kodu JavaScript ma właściwości generyczne np. funkcja map obsługująca tablice złożone z elementów dowolnego typu:

var lengthOfSecond = ["a", "bb", "ccc"].map(x => x.length)[1];

TypeScript 0.8 specjalnie traktując tablice z wnioskowaniem typu zmiennej lengthOfSecond sobie radził, ale ten mechanizm nie był dostępny dla innych bibliotek tj. underscore.js.

TypeScript 0.9 pozwala wyrazić w pełni intencje:

interface Array<T> { map<U>(callbackfn: (value: T, index: number, array: T[]) => U): U[]; }

var array: Array<string> = ["John", "Sam", "George"];

var lengths = array.map((val, idx, arr) => val.length);

Inny praktyczny przykład szybko odnajdziemy przy k.observable w Knockout.js.

Właściwości generyków:

  • tylko w czasie kompilacji
  • klasy, interfejsy i metody
  • referencje bez typu tak jak z typem any (np. Array to Array<any>)
  • sygnatury budujące i wywołujące także powinny być generyczne

 

Przeładowania na stałych

W JavaScript jest wiele metod, które w zależności od wartości przekazanego stringa zwracają inny typ. Przykładowo:

var canv = document.createElement('canvas');

W TypeScript 0.8 przed korzystaniem z canv trzeba było go jawnie zrzutować na typ HTMLCanvasElement. W TypeScript 0.9 dzięki definicji:

interface Document { createElement(tagName: string): HTMLElement; createElement(tagName: 'canvas'): HTMLCanvasElement; … }

nie jest to już potrzebne. Możliwe są przeładowania ze stałymi dla funkcji przyjmujących parametr typu string.

Nowy ficzer znajduje zastosowanie także przy stosowaniu listenerów. W TypeScript 0.8 w poniższej linijce ev jest wnioskowany jako ‘Event’:

document.addEventListener('mousemove', ev => { ev.clientX; });

W TypeScript 0.9 może być wnioskowany jako ‘MouseEvent’ dzięki definicji:

interface EventTarget { addEventListener(type: string, listener: (evt: Event) => void): void; addEventListener(type: 'mousemove', listener: (evt: MouseEvent) => void): void; … }

Przeładowania na stałych nie są dopuszczalne razem z ciałem funkcji.

 

Export =

Eksport klasy z modułu i jej bezpośredni import.

// client.ts
class Client {
constructor(public name: string, public description: string) { }
}
export = Client;

// app.ts
import MyClient = require('./client');
var myClient = new MyClient("Joe Smith", "My #1 client");

 

Typy wyliczeniowe

Ostateczna postać + konwersja z i na typ string.

enum Color { red, blue, green }

var myColor = Color.red;
console.log(Color[myColor]);

 

Łączenie deklaracji

Możliwość rozszerzenia statycznej strony klasy lub funkcji o nowe właściwości poprzez dopisanie definicji modułu o takiej samej nazwie.

function readInput(separator = readInput.defaultSeparator) {
   // read input
}
module readInput {
   export var defaultSeparator = ":";
}

Pozwala to wyrażać m.in takie konstrukcje jak klasy zagnieżdżone i funkcje ze statycznymi właściwościami.

 

Kompilator i serwis językowy

Nowa architektura kompilatora dostosowana do wydajnej obsługi dużych ilości kodu (powyżej 100 tys linii). Również serwis językowy został przepisany w większości na nowo w celu bardziej wydajnej obsługi. Lepsza wydajność IDE powoduje przejściowe nieco wolniejsze działanie kompilacji z linii komend (co zostanie poprawione w wersji 0.9.1)

 

Breaking changes

Wszystkie breaking changes można znaleźć tutaj. Najbardziej widoczne wydają mi się:

  1. Nowa nazwa typu logicznego - boolean. Nazwa ‘bool’ ma obecnie status deprecated (w wersji 0.9.1 nie będzie akceptowana)
  2. Składnia importu zewnętrznego modułu zawiera obecnie słowo ‘require’  tj.  import Utils = require('utils')
  3. Moduły wytwarzają obecnie jedynie przestrzenie nazw i wartości, nie mogą już tworzyć typów
  4. Generyki - typ Array jest teraz generyczny
  5. Pliki .d.ts - słowo ‘declare’ obecnie wymagane dla deklaracji najwyższego poziomu, które nie są interfejsami
  6. Plik 'node.d.ts' dystrybuowany z TypeScript 0.8 nie jest kompatybilny z wersją dołączoną do TypeScript 0.9

Brak komentarzy: