A TypeScript Type System főbb jellemzőit már ismertettük, amikor a Miért TypeScript? témát tárgyaltuk. Az alábbiakban bemutatunk néhány kulcsfontosságú megállapítást abból a beszélgetésből, amelyek nem szorulnak további magyarázatra:
-
A TypeScript típusrendszerét úgy terveztük, hogy opcionális legyen, hogy a JavaScripted TypeScript legyen.
-
A TypeScript nem blokkolja a JavaScript kibocsátását típushibák esetén, lehetővé téve, hogy fokozatosan frissítsd a JS-edet TS-re.
Most kezdjük a TypeScript típusrendszerének szintaxisával. Így azonnal elkezdheted használni ezeket az annotációkat a kódodban, és láthatod az előnyeit. Ez felkészít a későbbi mélyebb merülésre.
Mint már említettük, a típusokat a :TypeAnnotation szintaxis segítségével jegyzeteljük. Bármi, ami a típusdeklarációs térben elérhető, használható típusjelölésként.
A következő példa a változók, függvényparaméterek és függvényvisszatérési értékek típusjelöléseit mutatja be:
var num: number = 123;function identity(num: number): number {return num;}
Primitív típusok
A JavaScript primitív típusai jól reprezentáltak a TypeScript típusrendszerében. Ez az alábbiakban bemutatott string, number, boolean típusokat jelenti:
var num: number;var str: string;var bool: boolean;num = 123;num = 123.456;num = '123'; // Errorstr = '123';str = 123; // Errorbool = true;bool = false;bool = 'false'; // Error
Tömbök
A TypeScript külön típusszintaxist biztosít a tömbök számára, hogy megkönnyítse a kód megjegyzése és dokumentálása. A szintaxis alapvetően a utótagja bármely érvényes típusjelölésnek (pl. :boolean). Ez lehetővé teszi, hogy biztonságosan elvégezzen minden olyan tömbmanipulációt, amelyet általában elvégezne, és megvédi az olyan hibáktól, mint például egy rossz típusú tag hozzárendelése. Ezt az alábbiakban mutatjuk be:
var boolArray: boolean;boolArray = ;console.log(boolArray); // trueconsole.log(boolArray.length); // 2boolArray = true;boolArray = ;boolArray = 'false'; // Error!boolArray = 'false'; // Error!boolArray = ; // Error!
Interfaces
A TypeScriptben az interfaces az alapvető módja annak, hogy több típus annotációt egyetlen megnevezett annotációvá állítsunk össze. Tekintsük a következő példát:
interface Name {first: string;second: string;}var name: Name;name = {first: 'John',second: 'Doe'};name = { // Error : `second` is missingfirst: 'John'};name = { // Error : `second` is the wrong typefirst: 'John',second: 1337};
Itt a first: string + second: string annotációkat egy új Name annotációvá állítottuk össze, amely a típusellenőrzéseket az egyes tagokon érvényesíti. A TypeScriptben az interfészeknek rengeteg erejük van, és egy egész fejezetet szentelünk annak, hogyan használhatod ezt ki.
Inline Type Annotation
Ahelyett, hogy egy új interface-t hoznál létre, a :{ /*Structure*/ } segítségével inline annotálhatsz bármit, amit csak akarsz. Az előző példa ismét egy inline típussal bemutatott:
var name: {first: string;second: string;};name = {first: 'John',second: 'Doe'};name = { // Error : `second` is missingfirst: 'John'};name = { // Error : `second` is the wrong typefirst: 'John',second: 1337};
Az inline típusok kiválóan alkalmasak arra, hogy gyorsan megadjunk egy egyszeri típusmegjelölést valaminek. Megspórolja a (potenciálisan rossz) típusnév kitalálásának gondját. Ha azonban azon kapjuk magunkat, hogy ugyanazt a típusjelölést többször is inline adjuk meg, akkor jó ötlet megfontolni a refaktorálást egy interfésszé (vagy egy type alias később ebben a szakaszban tárgyalt
Speciális típusok
A már tárgyalt primitív típusokon túl van néhány olyan típus, amelynek különleges jelentése van a TypeScriptben. Ezek a any, null, undefined, void.
bármilyen
A any típus különleges helyet foglal el a TypeScript típusrendszerében. Ez egy menekülőnyílást ad a típusrendszerből, hogy megmondd a fordítónak, hogy húzzon el a fenébe. A any kompatibilis a típusrendszer minden típusával. Ez azt jelenti, hogy bármi hozzárendelhető, és bármihez hozzárendelhető. Ezt mutatja az alábbi példa:
var power: any;// Takes any and all typespower = '123';power = 123;// Is compatible with all typesvar num: number;power = num;num = power;
Ha JavaScript kódot portolsz TypeScriptre, akkor az elején szoros barátságot fogsz kötni a any-vel. Ezt a barátságot azonban ne vedd túl komolyan, mivel ez azt jelenti, hogy a típusbiztonság biztosítása rajtad múlik. Alapvetően azt mondod a fordítónak, hogy ne végezzen értelmes statikus elemzést.
null és undefined
Az, hogy a típusrendszer hogyan kezeli őket, a strictNullChecks fordítói flagtől függ (ezzel a flaggel később foglalkozunk). Amikor strictNullCheck:false, a null és undefined JavaScript literálokat a típusrendszer gyakorlatilag ugyanúgy kezeli, mint valami any típusú dolgot. Ezek a literálok bármely más típushoz hozzárendelhetők. Ezt mutatja az alábbi példa:
var num: number;var str: string;// These literals can be assigned to anythingnum = null;str = undefined;
:void
A :void használatával jelezhetjük, hogy egy függvénynek nincs visszatérési típusa:
function log(message): void {console.log(message);}
Generika
A számítástechnikában sok algoritmus és adatszerkezet nem függ az objektum tényleges típusától. Ennek ellenére mégis korlátozást akarunk érvényesíteni a különböző változók között. Egy egyszerű játékpélda egy olyan függvény, amely egy elemlistát vesz, és egy fordított elemlistát ad vissza. A megkötés itt a függvénynek átadott és a függvény által visszaadott adatok között van:
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; // Okayreversed = ; // Okay
Itt alapvetően azt mondjuk, hogy a reverse függvény egy T típusú tömböt (items: T) vesz (figyeljük meg a reverse<T> típusú paramétert) és egy T típusú tömböt ad vissza (figyeljük meg : T). Mivel a reverse függvény ugyanolyan típusú elemeket ad vissza, mint amilyen típusúakat felvesz, a TypeScript tudja, hogy a reversed változó is number típusú, és típusbiztonságot ad. Hasonlóképpen, ha egy string tömböt adunk át a fordított függvénynek, a visszaadott eredmény szintén egy string tömb lesz, és hasonló típusbiztonságot kapunk, mint az alábbiakban látható:
var strArr = ;var reversedStrs = reverse(strArr);reversedStrs = ; // Error!
Tény, hogy a JavaScript tömböknek már van egy .reverse függvényük, és a TypeScript valóban használja a generikusokat a struktúra meghatározására:
interface Array<T> {reverse(): T;// ...}
Ez azt jelenti, hogy a .reverse hívásakor bármilyen tömbön típusbiztonságot kapunk, ahogy az alábbiakban látható:
var numArr = ;var reversedNums = numArr.reverse();reversedNums = ; // Error!
A Array<T> interfészről később még többet fogunk beszélni, amikor a lib.d.ts-t bemutatjuk a Környezeti deklarációk fejezetben.
Union Type
A JavaScriptben elég gyakran szeretnénk lehetővé tenni, hogy egy tulajdonság többféle típusú legyen, például egy string vagy egy number. Itt jön jól az union típus (amelyet | jelöl egy típusmegjelölésben, pl. string|number). Gyakori felhasználási eset egy olyan függvény, amely egyetlen objektumot vagy az objektum tömbjét veheti pl.:
function formatCommandline(command: string|string) {var line = '';if (typeof command === 'string') {line = command.trim();} else {line = command.join(' ').trim();}// Do stuff with line: string}
A metszet típus
extend egy nagyon gyakori minta a JavaScriptben, ahol veszünk két objektumot és létrehozunk egy újat, amely rendelkezik mindkét objektum tulajdonságaival. Az Intersection Type lehetővé teszi, hogy ezt a mintát biztonságos módon használjuk az alábbiakban bemutatott módon:
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;
Tuple Type
A JavaScript nem rendelkezik első osztályú tuple támogatással. Az emberek általában csak egy tömböt használnak tuple-ként. A TypeScript típusrendszere pontosan ezt támogatja. A tuplikat a : stb. használatával lehet megjegyzésekkel ellátni. Egy tuple tetszőleges számú taggal rendelkezhet. A tuple-okat az alábbi példában mutatjuk be:
var nameNumber: ;// OkaynameNumber = ;// Error!nameNumber = ;
Ezt kombinálva a TypeScript destructuring támogatásával, a tuple-ok meglehetősen első osztályúnak tűnnek annak ellenére, hogy alatta tömbök:
var nameNumber: ;nameNumber = ;var = nameNumber;
Type Alias
A TypeScript kényelmes szintaxist biztosít olyan típusjelölések nevének megadásához, amelyeket több helyen is szeretnénk használni. Az aliasokat a type SomeName = someValidTypeAnnotation szintaxissal hozzuk létre. Egy példát az alábbiakban mutatunk be:
type StrOrNum = string|number;// Usage: just like any other notationvar sample: StrOrNum;sample = 123;sample = '123';// Just checkingsample = true; // Error!
A interface-től eltérően szó szerint bármilyen típusjelölésnek adhatunk típus alias-t (hasznos például union és intersection típusokhoz). Íme még néhány példa, hogy megismerkedjünk a szintaxissal:
type Text = string | { text: string };type Coordinates = ;type Callback = (data: string) => void;
TIP: Ha szükséged van a típusmegjelölések hierarchiájára, használj
interface-et. HasználhatókimplementsésextendsTIP: Egyszerűbb objektumstruktúrákhoz (mint
Coordinates) csak azért használjunk típus alias-t, hogy szemantikus nevet adjunk nekik. Akkor is, amikor szemantikus neveket akarsz adni az Union vagy Intersection típusoknak, a Type alias a megfelelő megoldás.
Összefoglaló
Most, hogy elkezdheted a JavaScript kódod nagy részének annotálását, belevethetjük magunkat a TypeScript Type Systemben elérhető összes hatalom aprólékos részleteibe.