TypeScript to nadzbiór języka JavaScript stworzony przez firmę Microsoft w 2012 roku. Udostępnia mechanizmy znane z najnowszego standardu ES6 oraz m.in. rozszerza możliwości języka o opcjonalne, statyczne typowanie. Jest kompilowany bezpośrednio do kompatybilnego z przeglądarkami kodu JavaScript.
Statyczne typowanie
JavaScript należy do języków dynamicznie typowanych. Oznacza to, że przy deklarowaniu zmiennej nie musimy określać jej typu, a w przeciągu działania aplikacji może się on kilkukrotnie zmienić. Działanie takie najczęściej nie jest pożądane, ponieważ może prowadzić do nieprzewidzianych błędów.
TypeScript jest językiem statycznie typowanym (opcjonalnie). Jeżeli określimy typ zmiennej, a następnie doprowadzimy do niezgodności typu, dowiemy się o tym na poziomie kompilacji (niektóre IDE od razu podpowiadają, że w danej linijce został popełniony błąd).
Typy podstawowe
TypeScript udostępnia nam trzy typy proste:
- boolean
- number
- string
Typy proste są przekazywane przez wartość. Typy referencyjne, złożone, przekazywane są przez referencję. W tym przypadku do dyspozycji mamy:
- array
- object
- tuple
Istnieją jeszcze inne typy, takie jak undefined
i null
, aczkolwiek ich użycie zazwyczaj nie ma większego sensu.
W TypeScript aby określić typ zmiennej, musimy zapisać go po znaku dwukropka:
let x: number;
let name: string;
let empty: boolean;
Deklaracja typu tablicowego wygląda tak:
let tab1: number[];
let tab2: Array<number>;
Natomiast tuple
następująco:
let tuple: [number, boolean, string];
Powyższy zapis oznacza, że pod indeksem 0 musi znajdować się wartość typu number
, pod indeksem 1 boolean
a 2 string
.
Inferencja typów
Na pierwszy rzut oka, mogłoby się wydawać, że TypeScript zmusza nas do pisania znacznie dłuższego kodu przez konieczność dopisywania typów w każdym miejscu – nawet tym najbardziej oczywistym. Nic bardziej mylnego. W wielu miejscach kompilator (jak i duża część IDE wspierających TS) jest w stanie „domyślić się” jaki jest typ zmiennej. Przykładowo w poniższym zapisie określanie typu jest zbędne:
const title: string = `Wartosc 2 + 2 wynosi 4`;
Jeżeli od razu przypisujemy wartość do zmiennej, w większości przypadków typ powinien zostać rozpoznany sam, tak więc ten zapis jest równoważny:
const title = `Wartosc 2 + 2 wynosi 4`;
Kiedy nie określimy typu i nie zostanie on rozpoznany, ustawiany jest typ any
.
Typ any
Zmienne typu any
są jak każda zmienna w czystym JavaScript – przyjmują dowolne wartości i w trakcie działania aplikacji, mogą zmieniać typ przechowywanej wartości. Jeżeli już zdecydowaliśmy się na korzystanie z TypeScript, typ any
powinniśmy unikać.
Funkcje
Wiemy już jak wygląda typowanie w przypadku zmiennych. Zapis funkcji wygląda następująco:
function multiply(a: number, b: number): number {
return a * b;
}
Oznacza to, że funkcja multiply
przyjmuje dwa parametry typu number
i zwraca wartość również o typie number
. Co w sytuacji gdy nasza funkcja ma nie zwracać żadnej wartości? W takim przypadku wykorzystamy typ void
znany z wielu innych języków programowania, m.in z C++ czy Javy.
function log(msg: string): void {
console.log(msg);
}
TypeScript oferuje nam jeszcze jedną możliwość – typ never
, który służy do oznaczania funkcji, które nigdy nie osiągną swojego końca. Do takiej sytuacji dochodzi wtedy, kiedy funkcja zawiera nieskończoną pętlę lub zawsze wyrzuca wyjątek. Przykład:
function infinity(): never {
while(true) {}
}
Rzutowanie
Wraz z typowaniem pojawia się mechanizm rzutowania (zmiany typu z jednego na drugi), aczkolwiek oprócz zapisu, nie ma on zbyt wiele wspólnego z innymi językami programowania. W TypeScript rzutowanie wykorzystujemy tylko wtedy, kiedy dojdzie do sytuacji, w której to my wiemy więcej o typie aniżeli kompilator. Sam mechanizm nie powoduje żadnych zmian w strukturze zmiennej. Do naszej dyspozycji udostępnione zostały dwa zapisy. Nieoceniony jest przykład wprost z dokumentacji:
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
Powyższy zapis jest równoważny z tym:
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
Podsumowanie
W tym artykule zapoznaliśmy się z podstawami dotyczącymi typowania w TypeScript. Poznaliśmy typy wbudowane i sposób ich wykorzystania. W następnej części zmierzymy się z wyzwaniem dotyczącym tworzenia własnych typów danych – typów wyliczeniowych, klas oraz interfejsów.