TypeScript, czyli pomoc w okiełznaniu JavaScript

Jak większość programistów, która wychowała się na tworzeniu aplikacji okienkowych nie jestem wielkim fanem JavaScirpt’u. Niemniej jednak język ten zyskuje coraz większą popularność, nie tylko wśród Web Developerów. Nie można zignorować tego jak bardzo największe firmy (takie jak Microsoft) zachęcają do tworzenia aplikacji mobilnych za pomocą HTML i JavaScript, dlatego myślę, że w niedługim czasie o ile już nie są, programiści tego języka będą bardzo cenni.

In JavaScript, arrays are objects, functions are objects, regular expressions are objects, and, of course, objects are objects.

Sam JavaScript jest językiem dla mnie językiem dziwnym. Można w nim zrobić rzeczy, o jakich nie śniło się nawet zwykłym programistom języków C – podobnych. Niestety zbyt duże możliwości jakie daje ten język nakładają się na to, że o wiele ciężej wykryć błąd w programie, bo tak na prawdę kompilator nie wie czy to błąd, czy użyliśmy tego specjalnie.

Programiści języków statycznie typowanych przyzwyczajeni są, że kompilator im krzyknie kiedy będą chcieli przesłać stringa, zamiast inta. Stety/niestety w JavaScripcie nie było takich możliwości. Ostatnio jednak coraz większą popularność zyskują biblioteki pozwalające na okiełznanie trochę samego JavaScript. Jedną z tych bibliotek, jest rozwijana przez Microsoft, TypeScript.

TypeScirpt

TypeScript w żaden sposób nie zastępuje kodu JS, jest bardziej rozszerzeniem jego składni. Edytor TypeScript wyświetla na raz zarówno kod TS jak i JS, dzięki czemu wiemy, czy na pewno chodzi nam o to co piszemy. Na stronie typescriptlang.org jest dostępnadokumentacja, z której możemy dowiedzieć się jakie funkcjonalności posiada biblioteka. W niniejszym poście postaram się przedstawić tylko największe zalety tego rozszerzenia.

Sprawdzanie typów

selekcja
JavaScript nie jest językiem silnie typowanym, więc zmienna, która jest napisem, za chwilę może być liczbą, lub funkcją. Tak samo zmienne przesyłane do funkcji nie mają w żaden sposób sprawdzanych typów. Tak więc jeśli chcemy być 100% pewni, że przesłana zmienna jest odpowiedniego typu musimy sprawdzać za każdym razem typy argumentów. Na szczęście TypeScript wprowadza możliwość określenia jakiego typu argumentu oczekujemy w funkcji. Nie pozwala to jednak korzystać z przesilania funkcji, bo koniec końców i tak cały kod jest konwertowany na JS.

function add(a: number, b : number){
   return a + b;
}
var sum = add(2, 3);    //OK
sum = add(2.1, 2.3e3);  //OK
sum = add(2, "Ola");    //ERR

Jest to najprostszy przykład sprawdzania argumentów przesłanych do funkcji, Warto jednak zauważyć, że błąd, który wyskoczy przy ostatnim wywołaniu funkcji, wyskakuje jedynie w edytorze TypeScript, więc jeśli ktoś chciałby użyć tej funkcji z poziomu zwykłego JavaScript operacja byłaby w pełni dozwolona, co więcej funkcja zwróciłaby wynik: “2Ola”.

Sprawdzanie typów nie ogranicza się tylko do wartości przychodzących do funkcji, można również określić jakiego typu zmienną, funkcja zwróci. Jeśli tego nie zadeklarujemy, kompilator sam sprawdzi jaki typ zwracamy i zmienną zadeklarowaną z wartości zwróconej będzie traktować jako właśnie takiego typu.

function add(a: number, b : number) : string{
   //return a + b;             //ERR
   return (a + b).toString();  //OK
}

Ostatnią rzeczą, odnośnie sprawdzania typów, którą zamierzam opisać to sprawdzanie jaką funkcję przesyłamy jako argument. Jak było wspomniane na początku w JS nawet funkcje są obiektami, więc często funkcje przesyła się jako parametr innej funkcji. Dzięki określeniu interfejsu funkcji możemy zadeklarować, że oczekujemy funkcji, która przyjmuje liczbę i zwraca liczbę. Jest to coś na kształt delegatów w języku C#.

function doSomething (arg : string, foo : (a : number) => number){
   return arg + " : " + foo(2).toString();
}
var foo2 = function (x : number){
   return "-" + x;
}
/*
Supplied parameters do not match any signature of call target: Call signatures of types
'(x: number) => string' and '(a: number) => number' are incompatible
*/
var res = doSomething("Jan", foo2);     //ERR

Klasy

u have no class
JavaScript jest językiem, w którym klasy określamy poprzez prototyp. Każdy obiekt, posiada swój prototyp, do którego możemy dodawać funkcje, przez co zyskujemy coś na kształt klas. Dziedzicznie natomiast jest tak zawiłe, że trzeba się sporo napisać, żeby osiągnąć wymagany efekt. Na szczęście TypeScript pomoże nam również z tym. Dzięki dobrze znanej z języków C-podobnych składni można definiować klasy, prywatne bądź publiczne zmienne, oraz metody. Poniższy przykład posiada: prywatną zmienną, konstruktor, publiczną metodę oraz prywatną metodę. Podobnie jak we wcześniejszym przypadkach, prywatne zmienne oraz metody są tylko umowne w kodzie TypeScript. Więc z poziomu kodu JavaScript można zarówno się odwołać do zmiennej name jak i wywołać metodę setName.

class MyClass {
   private name : string;

   constructor (nam : string){
      this.setName(nam);
   }
   getName() {
      return this.name;
   }
   private setName(value){
      this.name = value;
   }
}
var ob = new MyClass("Ala");
document.writeln(ob.getName());  
//Alaob.setName("Ola");  //ERR
ob.name = "Ola";    //ERR

Dziedziczenie

Dziedziczenie obiektów jest banalnie proste i oszczędza pisania bardzo wielu linijek kodu. Przykład ze strony typescriptlang.org świetnie pokazuje wszystkie zalety dziedziczenia.

class Animal {
   constructor(public name: string) { }
   move(meters: number) {
      alert(this.name + " moved " + meters + "m.");
   }
}
class Snake extends Animal {
   constructor(name: string) { super(name); }
   move() {
      alert("Slithering...");
      super.move(5);
   }
}
class Horse extends Animal {
   constructor(name: string) { super(name); }
   move() {
      alert("Galloping...");
      super.move(45);
   }
}

var sam = new Snake("Sammy the Python");
var tom: Animal = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);

W obu przypadkach zostaną wywołane funkcje przeciążające.

Intefejsy

Implementowanie interfejsów, chociaż podobne jest do dziedziczenia po klasach, to używane jest do trochę innych rzeczy. Dlatego twórcy TypeScript również pozwolili na tworzenie interfejsów w JavaScripcie. W interfejsach możemy deklarować zmienne bądź metody publiczne. Klasy implementujące te interfejsy muszą zagwarantować obsługę wszystkich metod oraz stworzenie zmiennych przedstawionych w interfejsie. Implementacja odbywa się za pomocą słówka implements, czyli po Javovemu.

interface SayHello {
   hello ();
}
class Animal {
   name : string;
   constructor (name : string){
      this.name = name;
   }
}
class Snake extends Animal implements SayHello{
   hello(){
      return ("ssss " + this.name + " ssss");
   }
}
class Duck extends Animal implements SayHello {
   hello (){
      return ("quack " + this.name + " quack");
   }
}

function echo (soundSource : SayHello){
   alert(soundSource.hello());
   alert(soundSource.hello());
}

var tom = new Snake ("Tom");
var james = new Duck("James");
echo(tom);
echo(james);

Dodatkowe linki
Aby móc korzystać z TypeScript w Visual Studio, trzeba najpierw pobrać plugin. Polecam również zainstalować dodatek do Visual Studio – Web Essentials 2012, który pozwoli na kompilacje kodu TS na JS z poziomu Visual Studio. Poza tym świetny edytor do nauki TypeScript można znaleźć na stronie domowej TypeScript.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

This site uses Akismet to reduce spam. Learn how your comment data is processed.