Abbiamo coperto le caratteristiche principali del sistema dei tipi di TypeScript quando abbiamo discusso Perché TypeScript? I seguenti sono alcuni punti chiave di quella discussione che non hanno bisogno di ulteriori spiegazioni:

  • Il sistema dei tipi in TypeScript è progettato per essere opzionale, in modo che il vostro JavaScript sia TypeScript.

  • TypeScript non blocca l’emissione di JavaScript in presenza di Type Errors, permettendovi di aggiornare progressivamente il vostro JS a TS.

Ora iniziamo con la sintassi del sistema di tipi TypeScript. In questo modo potete iniziare ad usare queste annotazioni nel vostro codice immediatamente e vederne il beneficio. Questo vi preparerà per un’immersione più profonda in seguito.

Come detto prima i tipi sono annotati usando la sintassi :TypeAnnotation. Tutto ciò che è disponibile nello spazio di dichiarazione dei tipi può essere usato come annotazione di tipo.

L’esempio seguente dimostra le annotazioni di tipo per le variabili, i parametri di funzione e i valori di ritorno di funzione:

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

Tipi primitivi

I tipi primitivi JavaScript sono ben rappresentati nel sistema di tipi TypeScript. Questo significa string, number, boolean come dimostrato di seguito:

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

Array

TypeScript fornisce una sintassi dei tipi dedicata agli array per rendere più facile per voi annotare e documentare il vostro codice. La sintassi consiste fondamentalmente nel posporre a qualsiasi annotazione di tipo valida (ad esempio :boolean). Vi permette di fare in modo sicuro qualsiasi manipolazione di array che fareste normalmente e vi protegge da errori come l’assegnazione di un membro del tipo sbagliato. Questo è dimostrato qui sotto:

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

Interfacce

Le interfacce sono il modo principale in TypeScript per comporre più annotazioni di tipo in una singola annotazione con nome. Considerate il seguente esempio:

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

Qui abbiamo composto le annotazioni first: string + second: string in una nuova annotazione Name che applica i controlli di tipo sui singoli membri. Le interfacce hanno molto potere in TypeScript e dedicheremo un’intera sezione a come usarle a vostro vantaggio.

Annotazione di tipo in linea

Invece di creare un nuovo interface potete annotare qualsiasi cosa vogliate in linea usando :{ /*Structure*/ }. L’esempio precedente presentato di nuovo con un tipo in linea:

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

I tipi in linea sono ottimi per fornire rapidamente un’annotazione unica per qualcosa. Vi risparmia il fastidio di inventare un nome di tipo (potenzialmente cattivo). Tuttavia, se ti ritrovi a mettere la stessa annotazione di tipo in linea più volte, è una buona idea considerare di rifattorizzarla in un’interfaccia (o un type alias trattato più avanti in questa sezione).

Tipi speciali

Oltre ai tipi primitivi che sono stati trattati, ci sono alcuni tipi che hanno un significato speciale in TypeScript. Questi sono any, null, undefined, void.

qualsiasi

Il tipo any occupa un posto speciale nel sistema dei tipi TypeScript. Ti dà una via di fuga dal sistema dei tipi per dire al compilatore di andare a farsi fottere. any è compatibile con qualsiasi tipo nel sistema dei tipi. Questo significa che qualsiasi cosa può essere assegnata ad esso ed esso può essere assegnato a qualsiasi cosa. Questo è dimostrato nell’esempio qui sotto:

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

Se state portando il codice JavaScript a TypeScript, all’inizio sarete molto amici di any. Tuttavia, non prendete questa amicizia troppo seriamente, perché significa che spetta a voi garantire la sicurezza dei tipi. State fondamentalmente dicendo al compilatore di non fare alcuna analisi statica significativa.

null e indefiniti

Come sono trattati dal sistema dei tipi dipende dal flag del compilatore strictNullChecks (trattiamo questo flag più avanti). Quando sono in strictNullCheck:false, i letterali JavaScript null e undefined sono effettivamente trattati dal sistema dei tipi come qualcosa di tipo any. Questi letterali possono essere assegnati a qualsiasi altro tipo. Questo è dimostrato nell’esempio seguente:

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

:void

Utilizzate :void per indicare che una funzione non ha un tipo di ritorno:

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

Generics

Molti algoritmi e strutture dati in informatica non dipendono dal tipo effettivo dell’oggetto. Tuttavia, si vuole ancora imporre un vincolo tra le varie variabili. Un semplice esempio giocattolo è una funzione che prende una lista di oggetti e restituisce una lista invertita di oggetti. Il vincolo qui è tra ciò che viene passato alla funzione e ciò che viene restituito dalla funzione:

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

Qui state fondamentalmente dicendo che la funzione reverse prende un array (items: T) di qualche tipo T (notate il parametro type in reverse<T>) e restituisce un array di tipo T (notate : T). Poiché la funzione reverse restituisce elementi dello stesso tipo che prende, TypeScript sa che la variabile reversed è anche di tipo number e vi darà la sicurezza del tipo. Allo stesso modo, se si passa un array di string alla funzione inversa, il risultato restituito è anch’esso un array di string e si ottiene una sicurezza di tipo simile, come mostrato di seguito:

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

In realtà gli array JavaScript hanno già una funzione .reverse e TypeScript usa effettivamente i generici per definire la sua struttura:

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

Questo significa che si ottiene la sicurezza del tipo quando si chiama .reverse su qualsiasi array come mostrato qui sotto:

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

Discuteremo di più sull’interfaccia Array<T> più tardi quando presenteremo lib.d.ts nella sezione Dichiarazioni ambientali.

Tipo di unione

Quasi comunemente in JavaScript si vuole permettere ad una proprietà di essere uno di più tipi, per esempio un string o un number. Questo è dove il tipo union (denotato da | in un’annotazione di tipo, ad esempio string|number) è utile. Un caso d’uso comune è una funzione che può prendere un singolo oggetto o un array di oggetti, ad esempio:

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

Intersection Type

extend è un modello molto comune in JavaScript dove si prendono due oggetti e se ne crea uno nuovo che ha le caratteristiche di entrambi. Un Intersection Type ti permette di usare questo pattern in modo sicuro come dimostrato qui sotto:

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

JavaScript non ha un supporto per le tuple di prima classe. La gente generalmente usa solo un array come tupla. Questo è esattamente ciò che il sistema di tipi TypeScript supporta. Le tuple possono essere annotate usando : ecc. Una tupla può avere qualsiasi numero di membri. Le tuple sono dimostrate nell’esempio seguente:

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

Combina questo con il supporto alla destrutturazione in TypeScript, le tuple sembrano abbastanza di prima classe nonostante siano array sotto:

var nameNumber: ;
nameNumber = ;
var = nameNumber;

Alias di tipo

TypeScript fornisce una sintassi conveniente per fornire nomi per annotazioni di tipo che vorresti usare in più di un posto. Gli alias sono creati usando la sintassi type SomeName = someValidTypeAnnotation. Un esempio è dimostrato qui sotto:

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

A differenza di un interface puoi dare un alias di tipo letteralmente a qualsiasi annotazione di tipo (utile per cose come tipi di unione e intersezione). Ecco qualche altro esempio per farvi familiarizzare con la sintassi:

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

TIP: Se avete bisogno di avere gerarchie di annotazioni di tipo usate un interface. Possono essere usati con implements e extends

TIP: Usa un alias di tipo per strutture di oggetti più semplici (come Coordinates) solo per dare loro un nome semantico. Anche quando vuoi dare nomi semantici ai tipi Union o Intersection, un alias di tipo è la strada da percorrere.

Ora che puoi iniziare ad annotare la maggior parte del tuo codice JavaScript, possiamo entrare nei dettagli di tutta la potenza disponibile nel Type System di TypeScript.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.