Przedstawiliśmy główne cechy systemu typów TypeScript, kiedy omawialiśmy Dlaczego TypeScript? Poniżej znajduje się kilka kluczowych wniosków z tej dyskusji, które nie wymagają dalszych wyjaśnień:

  • System typów w TypeScript został zaprojektowany jako opcjonalny, aby Twój JavaScript był TypeScript.

  • TypeScript nie blokuje emisji JavaScript w obecności błędów typu, pozwalając ci stopniowo aktualizować swój JS do TS.

Teraz zacznijmy od składni systemu typów TypeScript. W ten sposób możesz od razu zacząć używać tych adnotacji w swoim kodzie i zobaczyć korzyści. To przygotuje cię do głębszego nurkowania później.

Jak wspomniano wcześniej, typy są adnotowane przy użyciu składni :TypeAnnotation. Wszystko, co jest dostępne w przestrzeni deklaracji typu, może być użyte jako adnotacja typu.

Następujący przykład demonstruje adnotacje typu dla zmiennych, parametrów funkcji i wartości zwrotnych funkcji:

var num: number = 123;
function identity(num: number): number {
return num;
}

Typy prymitywne

Typy prymitywne JavaScript są dobrze reprezentowane w systemie typów TypeScript. Oznacza to string, number, boolean jak zademonstrowano poniżej:

var num: number;
var str: string;
var bool: boolean;
num = 123;
num = 123.456;
num = '123'; // Error
str = '123';
str = 123; // Error
bool = true;
bool = false;
bool = 'false'; // Error

Tablice

TypeScript zapewnia dedykowaną składnię typów dla tablic, aby ułatwić Ci adnotacje i dokumentowanie Twojego kodu. Składnia ta jest w zasadzie postfiksem do dowolnej poprawnej adnotacji typu (np. :boolean). Pozwala ci to bezpiecznie wykonywać dowolne manipulacje tablicowe, które normalnie byś robił i chroni cię przed błędami, takimi jak przypisanie członka niewłaściwego typu. Jest to zademonstrowane poniżej:

var boolArray: boolean;
boolArray = ;
console.log(boolArray); // true
console.log(boolArray.length); // 2
boolArray = true;
boolArray = ;
boolArray = 'false'; // Error!
boolArray = 'false'; // Error!
boolArray = ; // Error!

Interfejsy

Interfejsy są podstawowym sposobem w TypeScript do kompilacji wielu adnotacji typu w pojedynczą nazwaną adnotację. Weźmy pod uwagę następujący przykład:

interface Name {
first: string;
second: string;
}
var name: Name;
name = {
first: 'John',
second: 'Doe'
};
name = { // Error : `second` is missing
first: 'John'
};
name = { // Error : `second` is the wrong type
first: 'John',
second: 1337
};

Tutaj skomponowaliśmy adnotacje first: string + second: string w nową adnotację Name, która wymusza kontrolę typu na poszczególnych członkach. Interfejsy mają dużą moc w TypeScript i poświęcimy całą sekcję temu, jak możesz to wykorzystać na swoją korzyść.

Adnotacja typu inline

Zamiast tworzyć nową adnotację interface, możesz dodać adnotację do wszystkiego, co chcesz inline, używając :{ /*Structure*/ }. W poprzednim przykładzie ponownie przedstawiono typ inline:

var name: {
first: string;
second: string;
};
name = {
first: 'John',
second: 'Doe'
};
name = { // Error : `second` is missing
first: 'John'
};
name = { // Error : `second` is the wrong type
first: 'John',
second: 1337
};

Typy inline są świetne do szybkiego zapewnienia jednorazowej adnotacji typu dla czegoś. Oszczędza ci to kłopotów z wymyślaniem (potencjalnie złej) nazwy typu. Jednakże, jeśli znajdziesz się w umieszczaniu tej samej adnotacji typu inline wiele razy, dobrym pomysłem jest rozważenie refaktoryzacji do interfejsu (lub type alias omówionego później w tej sekcji).

Typy specjalne

Poza typami prymitywnymi, które zostały omówione, istnieje kilka typów, które mają specjalne znaczenie w TypeScript. Są to any, null, undefined, void.

any

Typ any zajmuje specjalne miejsce w systemie typów TypeScript. Daje ci on możliwość ucieczki z systemu typów, aby powiedzieć kompilatorowi, żeby się odwalił. any jest kompatybilny z każdym i wszystkimi typami w systemie typów. Oznacza to, że wszystko może być do niego przypisane i może być przypisane do czegokolwiek. Jest to zademonstrowane w poniższym przykładzie:

var power: any;
// Takes any and all types
power = '123';
power = 123;
// Is compatible with all types
var num: number;
power = num;
num = power;

Jeśli przenosisz kod JavaScript do TypeScript, będziesz bliskim przyjacielem any na początku. Jednak nie traktuj tej przyjaźni zbyt poważnie, ponieważ oznacza to, że to do Ciebie należy zapewnienie bezpieczeństwa typu. W zasadzie mówisz kompilatorowi, aby nie wykonywał żadnej sensownej analizy statycznej.

null i undefined

To, jak są one traktowane przez system typów, zależy od flagi kompilatora strictNullChecks (omawiamy tę flagę później). Kiedy w strictNullCheck:false, null i undefined literały JavaScript są efektywnie traktowane przez system typów tak samo jak coś typu any. Te literały mogą być przypisane do dowolnego innego typu. Jest to zademonstrowane w poniższym przykładzie:

var num: number;
var str: string;
// These literals can be assigned to anything
num = null;
str = undefined;

:void

Użyj :void do oznaczenia, że funkcja nie ma typu zwrotnego:

function log(message): void {
console.log(message);
}

Generics

Wiele algorytmów i struktur danych w informatyce nie zależy od rzeczywistego typu obiektu. Jednak nadal chcesz wymusić ograniczenia między różnymi zmiennymi. Prostym przykładem zabawki jest funkcja, która pobiera listę elementów i zwraca odwróconą listę elementów. Ograniczenie tutaj jest między tym, co jest przekazywane do funkcji, a tym, co jest zwracane przez funkcję:

function reverse<T>(items: T): T {
var toreturn = ;
for (let i = items.length - 1; i >= 0; i--) {
toreturn.push(items);
}
return toreturn;
}
var sample = ;
var reversed = reverse(sample);
console.log(reversed); // 3,2,1
// Safety!
reversed = '1'; // Error!
reversed = ; // Error!
reversed = 1; // Okay
reversed = ; // Okay

Tutaj w zasadzie mówisz, że funkcja reverse pobiera tablicę (items: T) jakiegoś typu T (zauważ parametr typu w reverse<T>) i zwraca tablicę typu T (zauważ : T). Ponieważ funkcja reverse zwraca elementy tego samego typu, jaki przyjmuje, TypeScript wie, że zmienna reversed jest również typu number i zapewni Ci bezpieczeństwo typu. Podobnie, jeśli przekażesz tablicę string do funkcji odwrotnej, zwrócony wynik jest również tablicą string i otrzymasz podobne bezpieczeństwo typu, jak pokazano poniżej:

var strArr = ;
var reversedStrs = reverse(strArr);
reversedStrs = ; // Error!

W rzeczywistości tablice JavaScript mają już funkcję .reverse i TypeScript rzeczywiście używa generycznych do określenia jej struktury:

interface Array<T> {
reverse(): T;
// ...
}

To oznacza, że otrzymujemy bezpieczeństwo typu podczas wywoływania .reverse na dowolnej tablicy, jak pokazano poniżej:

var numArr = ;
var reversedNums = numArr.reverse();
reversedNums = ; // Error!

Więcej na temat interfejsu Array<T> omówimy później, gdy przedstawimy lib.d.ts w rozdziale Deklaracje otoczenia.

Typ unii

Dość często w JavaScript chcesz pozwolić, aby właściwość była jednym z wielu typów np. a string lub a number. To jest miejsce, gdzie typ unii (oznaczany przez | w adnotacji typu, np. string|number) jest przydatny.

function formatCommandline(command: string|string) {
var line = '';
if (typeof command === 'string') {
line = command.trim();
} else {
line = command.join(' ').trim();
}
// Do stuff with line: string
}

Typ przecięcia

extend jest bardzo częstym wzorcem w JavaScript, gdzie bierzemy dwa obiekty i tworzymy nowy, który ma cechy obu tych obiektów. Typ Intersection pozwala na użycie tego wzorca w bezpieczny sposób, jak pokazano poniżej:

function extend<T, U>(first: T, second: U): T & U {
return { ...first, ...second };
}
const x = extend({ a: "hello" }, { b: 42 });
// x now has both `a` and `b`
const a = x.a;
const b = x.b;

Typ Tuple

JavaScript nie posiada obsługi tupli pierwszej klasy. Ludzie generalnie po prostu używają tablicy jako tuple. To jest dokładnie to, co wspiera system typów TypeScript. Tuple mogą być oznaczane za pomocą : itd. Tuple mogą mieć dowolną ilość członków. Tuple są zademonstrowane w poniższym przykładzie:

var nameNumber: ;
// Okay
nameNumber = ;
// Error!
nameNumber = ;

Połączenie tego z obsługą destrukturyzacji w TypeScript, tuple czują się dość pierwszą klasą, mimo że są tablicami pod spodem:

var nameNumber: ;
nameNumber = ;
var = nameNumber;

Alias typu

TypeScript zapewnia wygodną składnię do dostarczania nazw dla adnotacji typu, które chciałbyś użyć w więcej niż jednym miejscu. Aliasy są tworzone przy użyciu składni type SomeName = someValidTypeAnnotation. Przykład jest zademonstrowany poniżej:

type StrOrNum = string|number;
// Usage: just like any other notation
var sample: StrOrNum;
sample = 123;
sample = '123';
// Just checking
sample = true; // Error!

W przeciwieństwie do interface możesz nadać alias typu dosłownie każdej adnotacji typu (przydatne dla rzeczy takich jak typy unii i przecięcia). Oto kilka kolejnych przykładów, aby zapoznać cię ze składnią:

type Text = string | { text: string };
type Coordinates = ;
type Callback = (data: string) => void;

TIP: Jeśli potrzebujesz hierarchii adnotacji typu, użyj interface. Mogą być używane z implements i extends

TIP: Użyj aliasu typu dla prostszych struktur obiektów (jak Coordinates) tylko po to, aby nadać im semantyczną nazwę. Również, gdy chcesz nadać semantyczne nazwy typom Union lub Intersection, alias typu jest drogą do zrobienia.

Podsumowanie

Teraz, gdy możesz zacząć anotować większość swojego kodu JavaScript, możemy wskoczyć w najdrobniejsze szczegóły wszystkich mocy dostępnych w TypeScript’s Type System.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.