Typescript

Do testowania przykładów Typescript możemy użyć konsoli ts-node (https://www.npmjs.com/package/ts-node\. Instalujemy ją poleceniami:

npm install -g ts-node
npm install -g typescript

Uruchomienie:

ts-node --type-check

Typy danych

TypeScript wymaga jawnego podania typu danych w deklaracji zmiennych. Po nazwie zmiennej stawiamy dwukropek ( : ) i podajemy nazwę typu.

Przykłady.

let warunek : boolean = true;
let komunikat: string = 'Możesz użyć apostrofów';
let komunikat2: string = "... albo cuzysłowów";

Można też tworzyć wzorce pozwalajace na składanie napisów z elementów:

let wynik: string = `OK`;
let komunikat: string = `Wynik działania: ${wynik}.`

Liczby mogą być ałkowite, zmiennopzecinkowe, szesnastkowe, binarne i ósemkowe:

let integer: number = 38;
let decimal: number = 45.67;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;

Tablice

Typy tablic można zapisać na dwa różne sposoby:

let litery: string[] = ['A', 'B', 'C'];

lub jako typ tablicowy (znany z języka Java):

let litery: Array<string> = ['A', 'B', 'C'];

Krotki

Są to tablice z określoną liczbą elementów określonych z góry typów (słowo "krotka" pochodzi z teorii baz danych i odnosi się do wartości rekordu / wiersza tablicy).

let krotka: [number, string] = [1, 'jedynka'];

Proszę pamiętać, że kolejność elementów jest tu ważna! .

Wyliczeniowe

Typy wyliczeniowe to sposób na wprowadzenie symboli (stałych) zgromadzonych pod jednym identyfikatorem (nazwą typu wyliczeniowego). Odwołanie do wartości z użyciem znanej notacji kropkowej. Pod symbolami w definicji typu kryją się kolejne numery. Domyślnie wyliczenia zaczynają się od cyfry 0. Można to zmienić prez podstawienie - na przykład = 7:

> enum Numerki{ zero, jeden, siedem = 7, osiem };
> Numerki.jeden;
1
> Numerki.osiem;
8

Inne

  • any - dowolny typ,
  • void - nieokreślony (np. funkcja nie zwracająa wyniku),
  • never - nigdy (na przykład nieskończona pętla)
function infiniteLoop(): never {
    while (true) {
    }
    return 'to się nigdy nie wykona';
}

Typy parametrów i wyników funkcji

Do argumentów można dodać typy, a także typ zwracanej funkcji:

function iloraz(l: number, m: number): number {
   if (m==0) { return null; }
   else {  return l / m;}
}

Słowo kluczowe type

Słowo kluczowe type definiuje alias do typu.

> type liczba = number;
> type LiczbaLubNumer = string | liczba;  
> let n : liczba;
> let ln : LiczbaLubNumer;
> n=1
> ln=1
> ln='abc';
'abc'
> n='abc';
Thrown:  Unable to compile TypeScript
[eval].ts (1,1): Type '"abc"' is not assignable to type 'number'. (2322)

KLASY

Własności publiczne, prywatne, chronione

Do klas wprowadzonych przez ES6 TypeScript dodaje możliwość dzielenia własności na publiczne, prywatne i chronione:

  • Publiczny (public) - swobodny dostępny spoza klasy/obiektu (domyślnie).

  • Prywatne (private) - dostępne tylko w metodach implementowanych wewnątrz klasy.

  • Chronione (protected) - podobne do prywatnych, jednak dostępne z klas pochodnych

Przykład:

class Szyfr0 {
  private tajny: number;
  protected klucz: number;

  constructor(klucz: number) {
   this.klucz = klucz;
   this.tajny = 123;
  }
  szyfruj(x : number): number { return x + this.klucz + this.tajny; }
  deszyfruj(x : number): number { return x - this.klucz - this.tajny; }
}

class Szyfr1 extends Szyfr0 {
  szyfruj(x : number): number { return super.szyfruj(x) - this.klucz }
  deszyfruj(x : number): number { return super.deszyfruj(x) + this.klucz }
}

var koder = new Szyfr1(44);
alert(koder.szyfruj(9));

Zwróć uwagę na przedrostek super - powalający odwołać się do pól klasy nadrzędnej.

Właściwości statyczne

TypeScript pozwala również na definiowanie elementów statycznych na klasie. Oznacza to, że możesz użyć właściwości i metod, nawet jeśli nie tworzysz instancji klasy (czyli obiektu).

class Stala {
    static przedrostek: number = 48;
}
console.log(Stala.przedrostek);

Interfejsy

Interfejs jest opisem wymagań wobec definicji klasy/obiektu. Nie zawiera implementacji.

Przykład:

> interface Figura {
   rodzaj : string;
   wymiary : Array<number>;
 }
> class Kwadrat implements Figura { rodzaj = 'kwadrat'; wymiary=[]; }
> var k = new Kwadrat;
> console.log(k.rodzaj);
kwadrat

Dekoratory

Typescript wyprzedził rozwój języka Javascript, wprowadzając dekoratory własności, klas i parametrów.

Przykład wyjaśniający działanie dekoratorów:

function dekorator1(target: Object, propertyKey: string, 
                    descriptor: TypedPropertyDescriptor<any>) {
    let originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
            console.log('Wywołanie z parametrami:');
            console.log(args);
            return originalMethod.apply(this, args);
    };

    return descriptor;
}


class MyClass {

  @dekorator1
  public test(something : string) : string {
    return 'test z parametrem: ' + something;
  }

}

var o= new MyClass();
console.log(o.test('abc'));

Funkcja dekorator definiuje dekorator, którym następnie "dekorujemy" metodę "test" klasy MyClass. Taki mechanizm powoduje, że gdy użyjemy metody test(), zostanie wywołana funkcji podana jako wartość descriptor.value. Ona może wykonać jakieś dodatkowe operacje (tu - wypisuje paametry) i wtedy uruchomić właściwą funkcję. Najczęściej używa się tego mechanizmu do ustawienia domyślnych parametrów lub parametrów środowiska w którym funkcja działa.

Typy generyczne

W Typescript zaimplementowano znane z języka Java typy generyczne (generics) - czyli możliwość definiowania zmiennych i funkcji dla typów nieokreślonych ściśle. Można używać kilku typów, bez konieczności ich konwersji (rzutowania). Przy deklaracji i odwołaniu do takiego typu używamy nawiasów większy/mniejszy: <>.

> class C<T> {
   wlasnosc : T;
   public ustaw(w : T) { this.wlasnosc=w;}
   public czytaj():T {return this.wlasnosc}
 }
> let o1=new C<number>();
> o1.ustaw(1);
> o1.czytaj();
1
> let o2=new C<string>();
> o2.ustaw(1);
Thrown:  Unable to compile TypeScript
[eval].ts (1,10): Argument of type '1' is not assignable to parameter of type 'string'. (2345)
> o2.ustaw('1');
> o2.czytaj();
'1'

Możemy ograniczyć typy, jakie mogą być użyte - na przykład poprzez zastosowanie interfejsów. Służy do tego słowo kluczowe extends (jego znaczenie jest w tym miejscu nieco inne niż w przypadku definiowania klas). Na przykład (https://www.typescriptlang.org/docs/handbook/generics.html):

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}
loggingIdentity({length: 10, value: 3});

Powyżej zawarto tylko najważniejsze elementy Typescript, rozszerzające standard ES6. Dodatkowo można polecić na przykład opis: https://typeofweb.com/2016/07/11/typescript-czesc-1/