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
ésextends
TIP: 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.