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