Käsittelimme TypeScript-tyyppijärjestelmän tärkeimpiä ominaisuuksia käsitellessämme aiheen Miksi TypeScript?. Seuraavassa on muutama keskeinen ote tuosta keskustelusta, jotka eivät kaipaa enempää selitystä:

  • TypeScriptin tyyppijärjestelmä on suunniteltu valinnaiseksi niin, että JavaScriptisi on TypeScript.

  • TypeScript ei estä JavaScriptin emitointia tyyppivirheiden esiintyessä, jolloin voit asteittain päivittää JS:si TS:ksi.

Aloitetaanpa nyt TypeScript-tyyppijärjestelmän syntaksista. Näin voit heti alkaa käyttää näitä annotaatioita koodissasi ja nähdä hyödyn. Tämä valmistaa sinua syvällisempään sukellukseen myöhemmin.

Kuten aiemmin mainittiin, tyypit annotoidaan :TypeAnnotation-syntaksilla. Mitä tahansa, mikä on käytettävissä tyyppi-ilmoitusavaruudessa, voidaan käyttää Type-annotaationa.

Seuraavassa esimerkissä demonstroidaan muuttujien, funktioparametrien ja funktioiden paluuarvojen tyyppi-annotaatioita:

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

Primitiiviset tyypit

Javaskriptin primitiiviset tyypit ovat hyvin edustettuina TypeScriptin tyyppijärjestelmässä. Tämä tarkoittaa string, number, boolean kuten alla on havainnollistettu:

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

Arraytit

TypeScript tarjoaa oman tyyppisyntaksin arrayille, mikä helpottaa koodin kommentointia ja dokumentointia. Syntaksi on periaatteessa :n lisääminen minkä tahansa kelvollisen tyyppihuomautuksen jälkeen (esim. :boolean). Sen avulla voit tehdä turvallisesti kaiken tavanomaisen array-käsittelyn ja se suojaa sinua virheiltä, kuten väärän tyyppisen jäsenen osoittamiselta. Tätä havainnollistetaan alla:

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

Rajapinnat

Rajapinnat ovat TypeScriptin keskeinen tapa koota useita tyyppiannotaatioita yhdeksi nimetyksi annotaatioksi. Tarkastellaan seuraavaa esimerkkiä:

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

Tässä olemme sommitelleet annotaatiot first: string + second: string uudeksi annotaatioksi Name, joka pakottaa tyyppitarkastukset yksittäisille jäsenille. Rajapinnoilla on paljon valtaa TypeScriptissä, ja omistamme kokonaisen kappaleen sille, miten voit käyttää sitä hyödyksesi.

Inline-tyypin annotaatio

Uuden interface luomisen sijaan voit annotoida mitä tahansa haluamaasi inline-annotaatiota käyttämällä :{ /*Structure*/ }. Edellisessä esimerkissä esitettiin taas inline-tyyppi:

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-tyypit ovat loistavia, kun haluat nopeasti antaa jollekin asialle kertaluonteisen tyyppihuomautuksen. Se säästää (mahdollisesti huonon) tyyppinimen keksimisen vaivalta. Jos kuitenkin huomaat laittavasi saman tyyppi-annotaation inline useita kertoja, on hyvä idea harkita sen refaktorointia rajapinnaksi (tai type alias käsitellään myöhemmin tässä kappaleessa).

Erityistyypit

Käsiteltyjen primitiivityyppien lisäksi on muutamia tyyppejä, joilla on erityinen merkitys TypeScriptissä. Nämä ovat any, null, undefined, void.

kaikki

Tyypillä any on erityinen paikka TypeScriptin tyyppijärjestelmässä. Se antaa sinulle pakoluukun tyyppijärjestelmästä, jolla voit käskeä kääntäjää painumaan helvettiin. any on yhteensopiva kaikkien tyyppijärjestelmän tyyppien kanssa. Tämä tarkoittaa, että sille voidaan antaa mitä tahansa ja sille voidaan antaa mitä tahansa. Tätä havainnollistetaan alla olevassa esimerkissä:

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

Jos olet siirtämässä JavaScript-koodia TypeScriptiin, olet alussa läheinen ystävä any:n kanssa. Älä kuitenkaan ota tätä ystävyyttä liian vakavasti, sillä se tarkoittaa, että tyyppiturvallisuuden varmistaminen on sinun tehtäväsi. Käytännössä käsket kääntäjää olemaan tekemättä mitään mielekästä staattista analyysia.

null ja undefined

Miten tyyppijärjestelmä käsittelee niitä, riippuu kääntäjän strictNullChecks lipusta (käsittelemme tätä lippua myöhemmin). Kun se on strictNullCheck:false, tyyppijärjestelmä käsittelee null– ja undefined JavaScript-litteraaleja tehokkaasti samalla tavalla kuin jotain, jonka tyyppi on any. Nämä litteraalit voidaan liittää mihin tahansa muuhun tyyppiin. Tämä osoitetaan alla olevassa esimerkissä:

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

:void

Käytä :void merkitäksesi, että funktiolla ei ole paluutyyppiä:

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

Generics

Monet tietotekniikassa käytettävät algoritmit ja tietorakenteet eivät ole riippuvaisia objektin todellisesta tyypistä. Silti eri muuttujien välille halutaan silti asettaa jokin rajoitus. Yksinkertainen leluesimerkki on funktio, joka ottaa listan kohteita ja palauttaa käänteisen listan kohteita. Rajoitus tässä on sen välillä, mitä funktiolle syötetään ja mitä funktio palauttaa:

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

Tässä sanotaan periaatteessa, että funktio reverse ottaa joukon (items: T), joka on jotakin tyyppiä T (huomaa tyyppiparametri reverse<T>) ja palauttaa joukon, joka on tyyppiä T (huomaa : T). Koska reverse-funktio palauttaa elementtejä, jotka ovat samaa tyyppiä kuin se ottaa, TypeScript tietää, että reversed-muuttuja on myös tyypiltään number, ja antaa tyyppivarmuuden. Vastaavasti jos annat käänteisfunktiolle string-muotoisen matriisin, palautettu tulos on myös string-muotoinen matriisi ja saat samanlaisen tyyppiturvallisuuden, kuten alla on esitetty:

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

Tosiasiassa JavaScript-matriiseilla on jo .reverse-funktio, ja TypeScript tosiaankin käyttää geneerisiä ominaisuuksia määrittelemään sen rakenteen:

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

Tämä tarkoittaa, että saat tyyppiturvallisuuden kutsuessasi .reverse mitä tahansa arraya, kuten alla on esitetty:

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

Keskustelemme lisää Array<T>-rajapinnasta myöhemmin esitellessämme lib.d.ts:n osiossa Ambient Declarations.

Union-tyyppi

Javaskriptissä halutaan melko yleisesti sallia, että ominaisuus voi olla yksi useammasta tyypistä esim. string tai number. Tällöin union-tyyppi (jota merkitään | tyyppi-ilmoituksessa, esim. string|number) on kätevä. Yleinen käyttötapaus on funktio, joka voi ottaa yhden objektin tai objektin joukon esim:

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

Risteymätyyppi

extend on hyvin yleinen malli JavaScriptissä, jossa otetaan kaksi objektia ja luodaan uusi, jolla on molempien objektien ominaisuudet. Intersection Type mahdollistaa tämän kuvion käytön turvallisella tavalla, kuten alla on esitetty:

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

JavaScriptissa ei ole ensimmäisen luokan tuple-tukea. Ihmiset käyttävät yleensä vain arraya tuplina. TypeScript-tyyppijärjestelmä tukee juuri tätä. Tuplet voidaan merkitä käyttämällä : jne. Tuplilla voi olla kuinka monta jäsentä tahansa. Tuplia havainnollistetaan alla olevassa esimerkissä:

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

Yhdistämällä tämä TypeScriptin destrukturointitukeen, tuplat tuntuvat melko ensiluokkaisilta huolimatta siitä, että ne ovat alla olevia arrayjä:

var nameNumber: ;
nameNumber = ;
var = nameNumber;

Type Alias

TypeScript tarjoaa kätevän syntaksin, jolla voi antaa nimiä tyypin annotaatioille, joita haluaisi käyttää useammassa kuin yhdessä paikassa. Aliakset luodaan käyttämällä type SomeName = someValidTypeAnnotation-syntaksia. Esimerkki on esitetty alla:

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

Toisin kuin interface voit antaa tyypin aliaksen kirjaimellisesti mille tahansa tyyppiannotaatiolle (hyödyllinen esimerkiksi union- ja intersection-tyypeille). Tässä vielä muutama esimerkki, jotta tutustut syntaksiin:

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

TIP: Jos tarvitset hierarkkisia Type-merkintöjä, käytä interface. Niitä voidaan käyttää yhdessä implements ja extends

kanssa

TIP: Käytä tyyppialiaksia yksinkertaisemmille objektirakenteille (kuten Coordinates) vain antaaksesi niille semanttisen nimen. Myös silloin, kun haluat antaa semanttisia nimiä Union- tai Intersection-tyypeille, Type alias on oikea tapa.

Yhteenveto

Nyt kun voit alkaa annotoida suurimman osan JavaScript-koodistasi, voimme siirtyä TypeScriptin Type Systemin tarjoamien mahdollisuuksien yksityiskohtiin.

Vastaa

Sähköpostiosoitettasi ei julkaista.