Vi dækkede de vigtigste funktioner i TypeScript-typesystemet, da vi diskuterede Hvorfor TypeScript?. Følgende er et par centrale pointer fra den diskussion, som ikke behøver yderligere forklaring:

  • Typesystemet i TypeScript er designet til at være valgfrit, så dit JavaScript er TypeScript.

  • TypeScript blokerer ikke for JavaScript-emitering i tilfælde af typefejl, så du kan opdatere din JS gradvist til TS.

Nu skal vi begynde med syntaksen i TypeScript-typesystemet. På den måde kan du begynde at bruge disse annotationer i din kode med det samme og se fordelene. Dette vil forberede dig på et dybere dyk senere.

Som nævnt tidligere annoteres typer ved hjælp af :TypeAnnotation-syntaksen. Alt, der er tilgængeligt i typedeklarationsrummet, kan bruges som en typeannotation.

Det følgende eksempel demonstrerer typeannotationer for variabler, funktionsparametre og funktionsreturværdier:

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

Primitive typer

De primitive typer i JavaScript er godt repræsenteret i TypeScript-typesystemet. Det betyder string, number, boolean som vist nedenfor:

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

Arrays

TypeScript indeholder dedikeret typesyntaks for arrays for at gøre det lettere for dig at annotere og dokumentere din kode. Syntaksen består grundlæggende i at sætte som postfix til enhver gyldig typeannotation (f.eks. :boolean). Det giver dig mulighed for sikkert at udføre enhver array-manipulation, som du normalt ville gøre, og beskytter dig mod fejl som f.eks. at tildele et medlem af den forkerte type. Dette demonstreres nedenfor:

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

Interfaces

Interfaces er den centrale måde i TypeScript at sammensætte flere typeannotationer til en enkelt navngiven annotation. Overvej følgende eksempel:

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
};

Her har vi sammensat annotationerne first: string + second: string til en ny annotation Name, der håndhæver typekontrollen på de enkelte medlemmer. Interfaces har en masse magt i TypeScript, og vi vil dedikere et helt afsnit til, hvordan du kan bruge det til din fordel.

Inline typeannotation

I stedet for at oprette en ny interface kan du annotere alt, hvad du vil, inline ved hjælp af :{ /*Structure*/ }. Det foregående eksempel præsenteres igen med en inline-type:

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
};

Inline-typer er gode til hurtigt at give en engangsannotation om en type til noget. Det sparer dig for besværet med at finde på (et potentielt dårligt) typenavn. Men hvis du finder dig selv i at sætte den samme typeannotation inline flere gange, er det en god idé at overveje at refaktorisere den til en grænseflade (eller en type alias dækket senere i dette afsnit).

Særlige typer

Bortset fra de primitive typer, der er blevet dækket, er der et par typer, der har en særlig betydning i TypeScript. Disse er any, null, undefined, void.

nogen

Typen any har en særlig plads i TypeScript-typesystemet. Den giver dig en flugtvej fra typesystemet til at fortælle compileren, at den skal skride. any er kompatibel med alle typer i typesystemet. Det betyder, at alt kan tildeles til den, og den kan tildeles til alt. Dette demonstreres i eksemplet nedenfor:

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

Hvis du porterer JavaScript-kode til TypeScript, bliver du i begyndelsen gode venner med any. Du skal dog ikke tage dette venskab for alvorligt, da det betyder, at det er op til dig at sikre type-sikkerheden. Du fortæller i bund og grund compileren, at den ikke skal foretage nogen meningsfuld statisk analyse.

null og undefined

Hvordan de behandles af typesystemet afhænger af strictNullChecks compilerflaget (vi dækker dette flag senere). Når de er i strictNullCheck:false, behandles null og undefined JavaScript-litteralerne effektivt af typesystemet på samme måde som noget af typen any. Disse bogstaver kan tildeles enhver anden type. Dette demonstreres i nedenstående eksempel:

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

:void

Brug :void for at angive, at en funktion ikke har en returtype:

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

Generics

Mange algoritmer og datastrukturer inden for datalogi afhænger ikke af objektets faktiske type. Du ønsker dog stadig at håndhæve en begrænsning mellem forskellige variabler. Et simpelt legetøjseksempel er en funktion, der tager en liste af elementer og returnerer en omvendt liste af elementer. Begrænsningen her er mellem det, der er givet ind til funktionen, og det, der returneres af funktionen:

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

Her siger du grundlæggende, at funktionen reverse tager et array (items: T) af en vis type T (bemærk typeparameteren i reverse<T>) og returnerer et array af typen T (bemærk : T). Fordi funktionen reverse returnerer elementer af samme type som den tager, ved TypeScript, at variablen reversed også er af typen number, og den vil give dig Type-sikkerhed. På samme måde, hvis du indsender et array af string til den omvendte funktion, er det returnerede resultat også et array af string, og du får lignende type-sikkerhed som vist nedenfor:

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

I virkeligheden har JavaScript-arrays allerede en .reverse-funktion, og TypeScript bruger faktisk generics til at definere dens struktur:

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

Det betyder, at du får type-sikkerhed, når du kalder .reverse på et array, som vist nedenfor:

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

Vi vil diskutere mere om Array<T>-grænsefladen senere, når vi præsenterer lib.d.ts i afsnittet Ambient Declarations.

Union Type

I JavaScript er det ret almindeligt, at man ønsker at tillade, at en egenskab kan være en af flere typer, f.eks. en string eller en number. Det er her, at unionstypen (angivet med | i en typeannotation, f.eks. string|number) er nyttig. Et almindeligt anvendelsestilfælde er en funktion, der kan tage et enkelt objekt eller et array af objektet f.eks.:

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

Krydsningstypen

extend er et meget almindeligt mønster i JavaScript, hvor man tager to objekter og opretter et nyt, der har egenskaberne fra begge disse objekter. En Intersection Type giver dig mulighed for at bruge dette mønster på en sikker måde som vist nedenfor:

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;

Tupletype

JavaScript har ikke understøttelse af første klasses tupler. Folk bruger generelt bare et array som en tuple. Dette er præcis, hvad TypeScript-typesystemet understøtter. Tupler kan annoteres ved hjælp af : osv. En tuple kan have et vilkårligt antal medlemmer. Tupler demonstreres i nedenstående eksempel:

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

Kombinér dette med destruktureringsunderstøttelsen i TypeScript, så tupler føles ret førsteklasses på trods af at være arrays nedenunder:

var nameNumber: ;
nameNumber = ;
var = nameNumber;

Type Alias

TypeScript giver en praktisk syntaks til at give navne til typeannotationer, som du gerne vil bruge mere end ét sted. Aliasserne oprettes ved hjælp af type SomeName = someValidTypeAnnotation-syntaksen. Et eksempel er vist nedenfor:

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

I modsætning til en interface kan du give et typealias til bogstaveligt talt enhver typeannotation (nyttigt for ting som union- og intersektionstyper). Her er et par eksempler mere for at gøre dig fortrolig med syntaksen:

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

TIP: Hvis du har brug for hierarkier af typeannotationer, skal du bruge en interface. De kan bruges sammen med implements og extends

TIP: Brug et typealias for enklere objektstrukturer (som Coordinates), blot for at give dem et semantisk navn. Også når du vil give semantiske navne til Union- eller Intersection-typer, er et typealias den rigtige løsning.

Resumé

Nu, hvor du kan begynde at annotere det meste af din JavaScript-kode, kan vi springe ud i de små detaljer om alle de muligheder, der er tilgængelige i TypeScript’s Type System.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.