Javascript

TypeScript – wprowadzenie, typy proste i złożone

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.