JavaScript è il linguaggio di programmazione più ampiamente utilizzato per lo sviluppo web. Tuttavia, manca del supporto al type-checking, che è una caratteristica essenziale dei linguaggi di programmazione moderni.

JavaScript è stato originariamente progettato come un semplice linguaggio di scripting. La sua natura non rigorosa e l’assenza di cruciali funzionalità di Programmazione Orientata agli Oggetti (OOP) pongono alcune sfide per gli sviluppatori:

  1. Documentazione limitata e mancanza di auto-completamento.

  2. Incapacità di utilizzare concetti OOP.

  3. Mancanza di sicurezza dei tipi, che porta a errori in fase di esecuzione.

  4. Sfide nel refactoring e nella manutenzione.

  5. Assenza di interfacce e punti di integrazione.

TypeScript risolve questi problemi. È stato creato per rendere JavaScript un linguaggio di programmazione moderno più perfetto. Aiuta a migliorare l’esperienza dello sviluppatore, offre molte funzionalità utili e migliora l’interoperabilità.

Questo articolo approfondisce le basi di TypeScript. Ti insegnerò come installare TS e configurare un progetto. Poi affronteremo alcuni concetti fondamentali importanti. Imparerai anche come TypeScript viene compilato in JavaScript, rendendolo compatibile con i browser e gli ambienti Node.js.

Cosa affronteremo:

Prerequisiti

Prima di immergersi in TypeScript, è importante avere una comprensione di base di certi concetti per garantire un percorso di apprendimento più agevole. Mentre TypeScript potenzia JavaScript con il tipaggio statico e altre funzionalità potenti, si basa sui principi fondamentali di JavaScript. Ecco cosa dovresti sapere:

1. Fondamenti di JavaScript

TypeScript è un sovrainsieme di JavaScript, il che significa che estende le capacità di JavaScript. Per imparare efficacemente TypeScript, è necessario avere una solida comprensione dei concetti di base di JavaScript, inclusi:

  • Sintassi e tipi di dati: Capire come dichiarare variabili (let, const e var), lavorare con tipi primitivi (stringhe, numeri, booleani) e gestire array e oggetti.

  • Flusso di controllo: Essere familiari con i cicli (for, while), le condizioni (if-else, switch) e come controllano l’esecuzione del programma.

  • Funzioni: Sapere come definire e invocare funzioni, lavorare con parametri, valori di ritorno, e comprendere concetti come le funzioni freccia e le chiusure.

  • Programmazione Orientata agli Oggetti (OOP): Imparare a creare e lavorare con oggetti, classi, ed ereditarietà. Le funzionalità basate sulle classi di TypeScript si basano pesantemente sul modello OOP di JavaScript.

  • Gestione degli errori: Comprendere come utilizzare i blocchi try-catch per gestire gli errori in fase di esecuzione.

2. HTML e CSS di base

Anche se TypeScript è un linguaggio utilizzato principalmente con JavaScript, avere una conoscenza di base di HTML e CSS è utile, specialmente per i front-end developer. Questo perché la maggior parte dei progetti TypeScript coinvolgono la creazione o il lavoro con le applicazioni web

  • HTML: Comprendere come strutturare le pagine web utilizzando tag, attributi, ed elementi.

  • CSS: Imparare come stilizzare gli elementi utilizzando selettori, proprietà e valori. La familiarità con i framework CSS come Bootstrap è un vantaggio.

3. Familiarità con gli Strumenti di Sviluppo

  • Un editor di codice come Visual Studio Code, che ha un ottimo supporto per TypeScript ed estensioni.

  • Node.js e npm: Capire come configurare un ambiente di sviluppo, eseguire JavaScript al di fuori del browser e utilizzare npm (Node Package Manager) per installare le dipendenze.

  • Controllo versione (Git): Imparare i concetti di base di Git per tracciare le modifiche e collaborare in modo efficace su progetti TypeScript.

Come Iniziare – Come Installare TypeScript

Per iniziare a lavorare con TypeScript è necessario installarlo. Non è un processo complicato. Con TypeScript installato, è possibile sfruttarne la potenza per creare soluzioni di alta qualità.

È possibile installare TS in due modi:

  1. Installazione Globale: consente di accedere al compilatore da qualsiasi directory sul tuo computer. Per installare TypeScript globalmente, esegui il seguente comando:
npm install -g typescript

Questo comando sfrutta il gestore di pacchetti Node.js, npm. Installa TypeScript globalmente, rendendo il comando disponibile nella riga di comando.

  1. Installazione Locale: in questo caso, TypeScript viene installato solo all’interno di un progetto specifico. Questo metodo garantisce la compatibilità delle versioni e la coerenza tra i membri del team. Per installare TypeScript localmente, esegui il seguente comando:
npm install typescript --save-dev

Diversamente dall’installazione globale, questo comando installa TypeScript come dipendenza di sviluppo. Il comando tsc è disponibile solo per l’uso specifico del progetto, cioè il progetto specifico in cui si esegue il comando.

Puoi installare TypeScript senza problemi ora? Spero di sì!

Come Organizzare i Tuoi Progetti TypeScript

Organizzare un progetto TypeScript implica strutturare i suoi file con nomi e directory significativi, separare le preoccupazioni e utilizzare moduli per l’incapsulamento e la riutilizzabilità.

L’estensione .ts denota file TypeScript e contiene codice che si converte in JavaScript per l’esecuzione.

TypeScript supporta anche i file .d.ts, noti anche come file di definizione dei tipi. Questi file offrono informazioni sui tipi riguardanti librerie esterne JavaScript o moduli, contribuendo a una migliore verifica dei tipi e al completamento del codice, nonché migliorando l’efficienza dello sviluppo. Di seguito è riportato un esempio di una buona struttura del progetto TS:

my-ts-project/
├── src/ 
│   ├── components/ 
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── Modal.tsx
│   ├── services/ 
│   │   ├── api.ts
│   │   └── authService.ts
│   ├── utils/ 
│   │   ├── helpers.ts 
│   │   └── validators.ts
│   ├── models/ 
│   │   ├── User.ts
│   │   └── Product.ts
│   ├── index.tsx 
│   └── styles/ 
│       ├── global.css
│       └── theme.css
├── public/ 
│   ├── index.html
│   └── assets/ 
│       ├── images/
│       └── fonts/
├── tsconfig.json
└── package.json

Capiamo cosa sta succedendo qui:

  1. src/: Questa directory contiene tutto il codice sorgente del progetto.

    • components/: Contiene componenti UI riutilizzabili (ad esempio, Button, Input, Modal). Utilizzare .tsx (TypeScript JSX) consente di scrivere JSX con sicurezza dei tipi.

    • services/: Contiene servizi che interagiscono con API esterne o gestiscono la logica dell’applicazione (ad esempio, api.ts per chiamate API, authService.ts per l’autenticazione).

    • utils/: Contiene funzioni di aiuto e classi di utilità per compiti comuni (ad esempio, helpers.ts per la formattazione delle date, validators.ts per la validazione dell’input).

    • models/: Definisce interfacce o classi TypeScript per rappresentare strutture dati (ad esempio, User.ts, Product.ts).

    • index.tsx: Il punto di ingresso principale dell’applicazione.

    • styles/: Contiene file CSS o altri file di stile.

  2. public/: Questa directory contiene risorse statiche non elaborate da TypeScript (ad esempio, HTML, immagini, font).

  3. tsconfig.json: Il file di configurazione di TypeScript, specificando le opzioni del compilatore.

  4. package.json: Il file di manifesto del progetto, elenco delle dipendenze, script e altri metadati del progetto.

Solo una breve nota sulle convenzioni di denominazione in modo che tu le comprenda qui:

  • Usa PascalCase per i nomi delle classi (ad esempio, User, Product).

  • Usa camelCase per i nomi delle funzioni e delle variabili (ad esempio, getUser, firstName).

  • Utilizzare nomi significativi e descrittivi per file e directory.

Questa struttura favorisce la modularità, la riutilizzabilità e una migliore organizzazione, rendendo i tuoi progetti TypeScript più facili da mantenere e scalare.

Organizzare correttamente i tuoi progetti TS migliora la manutenibilità del codice, la leggibilità e la collaborazione nei flussi di lavoro di sviluppo TypeScript.

Come funziona il typing in TypeScript

Come qualsiasi altro linguaggio di programmazione tipizzato, TypeScript si basa su definizioni di tipo, generalmente chiamate Typing.

Il typing è un termine utilizzato in programmazione per definire i tipi di dati per variabili, parametri dei metodi e valori restituiti all’interno del codice.

Il typing ti consente di individuare rapidamente ed anticipatamente gli errori nello sviluppo, una capacità eccezionale che aiuta a mantenere una migliore qualità del codice.

Per specificare un tipo in TypeScript, inserisci due punti (:) e il tipo di dati desiderato dopo il nome della variabile. Ecco un esempio:

let age: number = 2;

La variabile sopra è dichiarata con il tipo number. In TypeScript, questo significa che può memorizzare solo numeri e nient’altro.

Tecniche di typing

In TypeScript, i dati possono essere tipizzati in due modi principali:

  1. Typing Statico: Il typing statico si riferisce alla specifica esplicita del tipo di dati delle variabili e di altre entità nel codice durante lo sviluppo. Il compilatore TypeScript applica queste definizioni di tipo, contribuendo a individuare precocemente gli errori correlati ai tipi. Ad esempio:
let age: number = 25;

Qui, la variabile age è esplicitamente dichiarata di tipo number. Questo garantisce che solo valori numerici possano essere assegnati ad essa, riducendo il rischio di errori in fase di esecuzione.

  1. Tipizzazione dinamica: La tipizzazione dinamica in TypeScript si riferisce a scenari in cui il tipo di una variabile è determinato a runtime. Questo può verificarsi quando le variabili vengono assegnate al tipo any, che consente loro di contenere valori di qualsiasi tipo. TypeScript non esegue il controllo del tipo nelle operazioni che coinvolgono variabili di tipo any.
let value: any;
value = 25; // Numero
value = "Hello"; // Stringa

Anche se TypeScript è principalmente un linguaggio staticamente tipizzato, la tipizzazione dinamica può essere comunque utile in casi specifici, come ad esempio:

  • Lavorare con librerie di terze parti che mancano di definizioni di tipo.

  • Interfacciarsi con dati strutturati in modo dinamico (ad esempio, risposte JSON da API con strutture sconosciute).

  • Prototipazione rapida o quando le informazioni sul tipo non sono disponibili durante la fase iniziale di sviluppo.

Tipizzazione Statica vs. Dinamica in TypeScript

La tipizzazione statica è significativamente più comune in TypeScript, poiché è una delle caratteristiche principali che differenzia TypeScript da JavaScript. Applicando controlli di tipo rigorosi, la tipizzazione statica migliora la manutenibilità del codice, riduce gli errori e aumenta la produttività dello sviluppatore.

La tipizzazione dinamica è tipicamente riservata ai casi in cui è richiesta flessibilità o quando si tratta di dati la cui struttura non può essere determinata in anticipo. Tieni presente che fare un uso eccessivo della tipizzazione dinamica (ad esempio, abusando del tipo any) è generalmente sconsigliato, poiché compromette i vantaggi del sistema di tipizzazione statica di TypeScript.

Quindi, mentre la tipizzazione dinamica ha il suo spazio in determinati casi particolari, la tipizzazione statica è l’approccio preferito e più comunemente utilizzato nello sviluppo in TypeScript.

Inferenza di tipo e Tipi Union

Inferenza di tipo

L’inferenza di tipo è una potente funzionalità di TypeScript che consente al compilatore di dedurre automaticamente il tipo di una variabile in base al valore assegnato durante l’inizializzazione. In parole semplici, TypeScript guarda al valore che assegni a una variabile e decide di che tipo dovrebbe essere, anche se non dichiari esplicitamente il tipo.

Per esempio:

typescriptCopyEditlet age = 25; // TypeScript deduce che 'età' è di tipo 'numero'
age = "hello"; // Errore: il tipo 'stringa' non è assegnabile al tipo 'numero'

In questo esempio, la variabile age viene automaticamente inferita come un number a causa del suo valore iniziale, 25. Qualsiasi tentativo di riassegnare age a un valore di un tipo diverso (come una stringa) causerà un errore di tipo.

La inferenza di tipo è particolarmente utile perché riduce la necessità di annotazioni esplicite sul tipo, rendendo il codice più pulito e leggibile. Tuttavia, fornisce comunque la sicurezza e l’affidabilità del controllo dei tipi di TypeScript.

Quando utilizzare l’inferenza di tipo:
  • Assegnazioni semplici: Utilizzare l’inferenza di tipo per assegnazioni dirette in cui il tipo è ovvio dal valore.

  • Valori predefiniti: Quando si forniscono valori predefiniti per variabili o parametri di funzione, l’inferenza di tipo garantisce che il tipo corretto venga applicato senza richiedere annotazioni manuali.

  • Prototipazione rapida: Durante le prime fasi di sviluppo, l’inferenza di tipo può ridurre il codice ripetitivo pur garantendo la sicurezza dei tipi.

Tipi Union

I tipi di unione consentono a una variabile di contenere valori di tipi multipli. Sono definiti inserendo una barra verticale (|) tra i tipi. Questa funzionalità è particolarmente utile quando una variabile può legittimamente avere più di un tipo durante il suo ciclo di vita.

Per esempio:

typescriptCopyEditlet numOrString: number | string; // 'numOrString' può contenere sia un numero che una stringa
numOrString = 25; // Valido
numOrString = "hello"; // Valido
numOrString = true; // Errore: Il tipo 'boolean' non è assegnabile al tipo 'number | string'

È possibile definire anche tipi di unione con più di due tipi possibili:

typescriptCopyEditlet multiType: number | string | boolean;
multiType = 42; // Valido
multiType = "TypeScript"; // Valido
multiType = false; // Valido
Quando utilizzare i tipi di unione:
  • Parametri di funzione flessibili: Quando una funzione può accettare più tipi di input.

      typescriptCopyEditfunction printValue(value: string | number) {
        console.log(value);
      }
    
  • Gestione delle diverse strutture dati: Quando si lavora con API o fonti di dati esterne in cui i campi possono variare in tipo.

  • Variabili opzionali o a più stati: Ad esempio, una variabile che può rappresentare uno stato di caricamento come booleano, un errore come stringa, o dati validi come un oggetto:

      typescriptCopyEditlet status: boolean | string | { success: boolean; data: any };
    

Come Gestire Oggetti, Array e Tipi di Funzione in TypeScript

Per padroneggiare TypeScript, è necessario comprendere i vari tipi di dati supportati in TypeScript e come e quando utilizzarli.

I tipi primitivi di JavaScript come stringhe, numeri, booleani e altri definiscono anche i fondamentali mattoni di dati in TypeScript. Ma in particolare, Oggetti, Array, e Funzioni sono essenziali per costruire applicazioni robuste. Con oggetti, array e funzioni, puoi gestire meglio i dati e utilizzarli in modo efficiente nello sviluppo.

Tipi di Oggetti in TypeScript

I tipi di oggetti rappresentano il progetto per creare oggetti in TypeScript. Puoi utilizzare gli oggetti per definire la loro struttura, simile a come si usano le classi nella programmazione orientata agli oggetti (OOP). Ma gli oggetti mancano degli aspetti comportamentali e dell’incapsulamento che le classi offrono.

Per definire un tipo di oggetto, definisci esplicitamente il progetto dell’oggetto dopo i due punti (:). Ad esempio:

// Inizializzazione del Tipo Oggetto

let student: {
    name: string;
    age: number;
    matricNumber: string | number;
 };

// Assegnazione dell'Oggetto con dati reali

student = {
    name: "Akande"
    age: 21,
    matricNumber: 21/52 + "HP" + 19,
};

Nota che le proprietà terminano con un punto e virgola; invece di una virgola ,, che le conclude in un oggetto reale.

Quello sopra è il modo principale per definire un oggetto in TypeScript. Un altro modo è utilizzare le interfacce, che tratterò più avanti in questo articolo.

Tipi di Array in TypeScript

Gli array in TypeScript ti permettono di memorizzare valori multipli dello stesso tipo o di tipi diversi in una singola variabile. Migliorano la sicurezza e la chiarezza del tuo codice imponendo la coerenza dei tipi tra gli elementi dell’array.

In TypeScript, i tipi di array possono essere definiti in due modi:

1. Utilizzando il modello Array<tipo>

Questa sintassi utilizza il tipo generico Array, dove tipo rappresenta il tipo di elementi che l’array può contenere.

typescriptCopyEditlet numbers: Array<number> = [1, 2, 3, 4, 5];
let mixedArray: Array<number | string> = [1, 2, 3, 4, 5, "Hello"];
  • Esempio di numeri: Questo array può contenere solo numeri. Tentare di aggiungere una stringa o un altro tipo a questo array comporterà un errore di tipo.

      typescriptCopyEditnumeri.push(6); // Valido
      numeri.push("Ciao"); // Errore: Il tipo 'stringa' non è assegnabile al tipo 'numero'
    
  • mixedArray Esempio: Questo array utilizza un tipo di unione (number | string), consentendo di memorizzare sia numeri che stringhe.

      typescriptCopyEditmixedArray.push(42); // Valido
      mixedArray.push("TypeScript"); // Valido
      mixedArray.push(true); // Errore: Il tipo 'boolean' non è assegnabile al tipo 'number | string'
    

2. Utilizzo del type[] modello

Questa sintassi aggiunge parentesi quadre ([]) al tipo degli elementi che l’array può contenere.

typescriptCopyEditconst numbers: number[] = [1, 2, 3, 4, 5];
const mixedArray: (string | number)[] = [1, 2, 3, 4, 5, "Hello"];
  • numbers Esempio: Simile all’esempio Array<number>, questo array può contenere solo numeri.

      typescriptCopyEditnumbers[0] = 10; // Valido
      numbers.push("Ciao"); // Errore: Il tipo 'string' non è assegnabile al tipo 'number'
    
  • mixedArray Esempio: Come il precedente mixedArray, questo array consente sia numeri che stringhe, offrendo flessibilità dove il tipo di dati può variare.

      typescriptCopyEditmixedArray[1] = "Mondo"; // Valido
      mixedArray.push(true); // Errore: Il tipo 'boolean' non è assegnabile al tipo 'string | number'
    

Come Usare Gli Array in TypeScript

Gli array sono versatili e comunemente utilizzati per memorizzare collezioni di dati correlati. Ecco alcuni scenari pratici:

Memorizzazione di Dati Omogenei:
Quando tutti gli elementi nell’array condividono lo stesso tipo, come ad esempio un elenco di ID utente o prezzi dei prodotti:

typescriptCopyEditconst userIds: number[] = [101, 102, 103];
const productPrices: Array<number> = [29.99, 49.99, 19.99];

Memorizzazione dei dati eterogenei:
Quando gli elementi possono avere tipi diversi, come ad esempio una lista di messaggi contenente testo e metadati opzionali:

typescriptCopyEditconst messages: (string | object)[] = [
  "Welcome",
  { type: "error", text: "Something went wrong" },
];

Iterare sugli array:
Gli array in TypeScript possono essere utilizzati in cicli con piena sicurezza di tipo:

typescriptCopyEditconst scores: number[] = [80, 90, 70];
scores.forEach((score) => console.log(score + 5)); // Aggiunge 5 a ogni punteggio

Parametri di funzione e tipi di ritorno:
Gli array possono anche essere passati come parametri di funzione o restituiti da funzioni con tipizzazione rigorosa:

typescriptCopyEditfunction getNumbers(): number[] {
  return [1, 2, 3];
}
function printStrings(strings: string[]): void {
  strings.forEach((str) => console.log(str));
}

Tipi di funzione in TypeScript

I tipi di funzione in TypeScript descrivono la forma delle funzioni, inclusi i tipi dei parametri e dei valori restituiti. I tipi di funzione sono definiti specificando esplicitamente i tipi dei parametri durante la dichiarazione. Il tipo di ritorno è specificato aggiungendo : e il tipo da restituire immediatamente dopo le parentesi. Ad esempio:

function addition (a: number, b: number): number {
return a + b;
}

La funzione sopra prende due numeri, li somma e restituisce un numero. La funzione non funzionerà se uno qualsiasi dei suoi argomenti non è un numero e se restituisce qualcos’altro rispetto a un numero. Ad esempio:

  1. Chiamare la funzione con una stringa come argomento:
// Questo non funzionerà perché si aspetta numeri, e uno degli argomenti è una stringa

addition(1, "two");
  1. Riscrivere la funzione per restituire una stringa:
// La funzione restituirà un errore perché sta restituendo una stringa

function addition (a: number, b: number): string {
    let result = a + b;
    let returnStatement = `Addition of ${a} and ${b} is: ${result}`;
    return returnStatement;
}

Prova tu stesso il codice per vedere come funzionano questi esempi.

Comprendere e gestire efficacemente oggetti, array e funzioni in TypeScript ti permette di scrivere codice sicuro e manutenibile, migliorando l’affidabilità e la scalabilità delle tue applicazioni.

Come Creare Tipi Personalizzati in TypeScript

Spesso, il tuo modello di progettazione non segue i tipi di dati incorporati in TypeScript. Ad esempio, potresti avere modelli che utilizzano la programmazione dinamica. E questo può causare problemi nel tuo codice. TypeScript offre una soluzione per creare tipi personalizzati per affrontare questa problematica.

I tipi personalizzati ti permettono di definire la struttura dei tuoi dati e le forme secondo le tue esigenze. Ciò migliora la leggibilità e la manutenibilità del codice.

La Parola Chiave Type

La parola chiave type ti consente di creare alias di tipo, fornendo un modo per creare tipi personalizzati. I tipi che crei possono essere riutilizzati in tutto il tuo codice. Gli alias di tipo aiutano a definire tipi di unione o a combinare tipi in alias singoli. La sintassi per creare un tipo personalizzato è la seguente:

// Sintassi

type TypeAlias = type;

Ecco un esempio:

Il codice sopra crea un tipo personalizzato UserName, una unione di numeri e stringhe. Utilizza il tipo creato per definire due variabili relativamente per verificare se il tipo funziona.

Si raccomanda di iniziare un alias di tipo con una lettera maiuscola.

La parola chiave Type è generalmente utilizzata per i tipi primitivi – ma come creare un tipo di oggetto personalizzato?

Qui entrano in gioco gli Interfacce.

Interfacce TypeScript

Le interfacce in TypeScript vengono utilizzate per definire la struttura degli oggetti. Servono come schemi, specificando le proprietà che un oggetto dovrebbe avere e i rispettivi tipi. Questo garantisce che gli oggetti rispettino una forma coerente, consentendo la sicurezza dei tipi e un codice più chiaro.

Definizione di un’interfaccia

Un’interfaccia è definita utilizzando la parola chiave interface. La sintassi è la seguente:

typescriptCopyEditinterface InterfaceName {
  property1: Type;
  property2: Type;
}

Esempio:

typescriptCopyEditinterface User {
  id: number;
  name: string;
  email: string;
}

const user: User = {
  id: 1,
  name: "Alice",
  email: "[email protected]",
};

Ecco cosa succede in questo esempio:

  1. Dichiarazione dell’interfaccia (interface User):

    • Qui definiamo uno schema per un oggetto User. Specifica che qualsiasi oggetto di tipo User deve avere le seguenti proprietà:

      • id di tipo number

      • name di tipo string

      • email di tipo string

  2. Utilizzando l’interfaccia (const user: User):

    • Dichiariamo un oggetto user di tipo User.

    • L’oggetto deve avere tutte le proprietà definite nell’interfaccia User, con valori dei tipi specificati. Se una proprietà manca o il suo tipo non corrisponde, TypeScript genererà un errore in fase di compilazione.

Per esempio:

    typescriptCopyEditconst invalidUser: User = {
      id: 1,
      name: "Alice",
      // Errore: Proprietà 'email' mancante nel tipo
    };

Quindi potresti chiederti – perché dovresti usare le interfacce?

  • Sicurezza del tipo: Garantisce che gli oggetti rispettino la struttura prevista, evitando errori in fase di esecuzione.

  • Riusabilità: La stessa interfaccia può essere riutilizzata in diverse parti dell’applicazione, riducendo la duplicazione.

  • Chiarezza del codice: Rende il codice più facile da leggere e comprendere descrivendo esplicitamente la forma degli oggetti.

Funzionalità avanzate delle interfacce

  1. Proprietà opzionali: Puoi rendere le proprietà opzionali aggiungendo un punto interrogativo (?).

     typescriptCopyEditinterface Prodotto {
       id: number;
       nome: string;
       descrizione?: string; // Proprietà opzionale
     }
    
     const prodotto: Prodotto = {
       id: 101,
       nome: "Laptop",
     }; // Valido, poiché 'descrizione' è opzionale
    
  2. Proprietà di sola lettura: Usa readonly per impedire la modifica delle proprietà dopo l’inizializzazione.

     typescriptCopyEditinterface Punto {
       readonly x: number;
       readonly y: number;
     }
    
     const punto: Punto = { x: 10, y: 20 };
     punto.x = 15; // Errore: Impossibile assegnare a 'x' perché è una proprietà di sola lettura
    
  3. Estensione delle interfacce: Le interfacce possono ereditare proprietà da altre interfacce, consentendo la composizione.

     typescriptCopyEditinterface Persona {
       nome: string;
       età: number;
     }
    
     interface Impiegato estende Persona {
       idImpiegato: number;
     }
    
     const impiegato: Impiegato = {
       nome: "John",
       età: 30,
       idImpiegato: 1234,
     };
    

Quando utilizzare le interfacce

Esistono vari scenari in cui è una buona idea utilizzare le interfacce. Puoi utilizzarle quando desideri definire e far rispettare la struttura degli oggetti passati nel tuo codice.

Sono utili anche nelle risposte API, poiché ti aiutano a controllare il tipo degli oggetti ricevuti dalle API. Ciò garantisce che i dati siano conformi alle tue aspettative.

Le interfacce sono anche utili quando si lavora con tipi riutilizzabili. Quando più parti della tua applicazione utilizzano oggetti con la stessa struttura, le interfacce impediscono la duplicazione.

Sfruttando le interfacce, puoi creare applicazioni robuste, manutenibili e sicure dal punto di vista dei tipi. Sono una caratteristica essenziale di TypeScript che promuove codice pulito e prevedibile.

Generici e tipi letterali

I generici in TypeScript ti consentono di creare componenti riutilizzabili che possono funzionare con vari tipi di dati. Ti permettono di scrivere funzioni, classi e interfacce senza specificare il tipo esatto in anticipo, rendendo il tuo codice più flessibile e manutenibile.

Ecco un esempio di una funzione generica e di un’interfaccia generica in TypeScript:

// Interfaccia generica per una scatola che può contenere qualsiasi valore 

interface  Box<T> { 
    value: T; 
}

// Esempi di utilizzo

let  numberBox: Box<number> = { value: 10 };
let  stringBox: Box<string> = { value: "TypeScript" };

console.log(numberBox.value); // Output: 10  
console.log(stringBox.value); // Output: TypeScript

Puoi utilizzare i generici quando non sei sicuro del tuo tipo di dati.

A differenza dei Generics, i tipi letterali ti consentono di specificare i valori esatti che una variabile può contenere. Questo aggiunge maggiore specificità e sicurezza al tipo nel tuo codice, impedendo che vengano assegnati valori indesiderati. Ecco un esempio:

type Direction = 'up' | 'down' | 'left' | 'right';

Una variabile creata con il tipo sopra può essere assegnata solo alle stringhe up, down, left e right.

In generale, sfruttare tipi personalizzati in TypeScript ti consente di creare strutture dati espressive, riutilizzabili e sicure dal punto di vista del tipo, aiutandoti a sviluppare applicazioni più robuste e manutenibili.

Come unire tipi in TypeScript

Unire tipi in TypeScript combina più dichiarazioni di tipo in un unico tipo unificato. Questa capacità consente ai programmatori di costruire tipi complessi da pezzi più piccoli e riutilizzabili, migliorando la chiarezza del codice, la riutilizzabilità e la manutenibilità.

1. Unione di dichiarazioni nelle interfacce

TypeScript supporta la unione di dichiarazioni, dove più dichiarazioni di interfaccia con lo stesso nome vengono automaticamente combinate in un’unica interfaccia. Ciò ti consente di ampliare un’interfaccia esistente definendo proprietà o metodi aggiuntivi.

Esempio:
typescriptCopyEditinterface User {
  id: number;
  name: string;
}

interface User {
  email: string;
}

const user: User = {
  id: 1,
  name: "Alice",
  email: "[email protected]",
};
Come funziona:
  • L’interfaccia User è dichiarata due volte, ciascuna con proprietà diverse.

  • TypeScript fonde automaticamente queste dichiarazioni in un’unica interfaccia:

  • Quando si crea l’oggetto user, tutte le proprietà dell’interfaccia fusa devono essere presenti. Se manca una qualsiasi proprietà, TypeScript genererà un errore.

La fusione delle dichiarazioni è particolarmente utile quando si lavora con librerie di terze parti. È possibile estendere o aggiungere nuove proprietà a un’interfaccia esistente senza modificare il codice sorgente della libreria.

2. Fusione delle Interfacce Utilizzando la Parola Chiave extends

La parola chiave extends consente a un’interfaccia di ereditare proprietà e metodi da un’altra, creando una nuova interfaccia che combina le proprietà di entrambe.

Esempio:
typescriptCopyEditinterface Person {
  name: string;
  age: number;
}

interface Employee extends Person {
  employeeId: number;
}

const employee: Employee = {
  name: "John",
  age: 30,
  employeeId: 101,
};
Come funziona:
  • L’interfaccia Person definisce due proprietà: name e age.

  • L’interfaccia Employee utilizza la parola chiave extends per ereditare le proprietà da Person.

  • L’interfaccia Employee aggiunge anche una nuova proprietà, employeeId.

  • L’oggetto employee deve includere tutte le proprietà sia di Person che di Employee.

Questo approccio è ideale per le relazioni gerarchiche. Ad esempio, è possibile definire un’interfaccia di base per le proprietà condivise ed estenderla per tipi specializzati.

3. Unione di Tipi Utilizzando l’Operatore &

L’operatore &, noto come tipo di intersezione, consente di combinare più tipi in un’unica entità. Il tipo risultante include tutte le proprietà e i metodi di ciascun tipo.

Esempio:
typescriptCopyEdittype Address = {
  city: string;
  country: string;
};

type ContactInfo = {
  email: string;
  phone: string;
};

type EmployeeDetails = Address & ContactInfo;

const employee: EmployeeDetails = {
  city: "New York",
  country: "USA",
  email: "[email protected]",
  phone: "123-456-7890",
};
Come funziona:
  • Indirizzo e InfoContatto sono due tipi separati.

  • DettagliDipendente è un tipo di intersezione creato utilizzando Indirizzo & InfoContatto.

  • L’oggetto dipendente deve includere tutte le proprietà sia di Indirizzo che di InfoContatto. Proprietà mancanti o con tipi non corretti causeranno un errore in TypeScript.

I tipi di intersezione sono utili quando è necessario combinare tipi non correlati o creare tipi compositi per casi d’uso specifici, come risposte API che uniscono diverse strutture dati.

Quando Utilizzare Ciascuno di Questi Approcci

  1. Fusione di dichiarazioni: Utilizzare quando si desidera estendere o aumentare un’interfaccia esistente, in particolare in librerie di terze parti o codebase condivise.

  2. estende parola chiave: Utilizzare per relazioni gerarchiche dove un’interfaccia di base può essere specializzata in tipi più specifici.

  3. Tipi di intersezione (&): Da utilizzare quando è necessario combinare più tipi non correlati in un unico tipo per casi d’uso specifici.

Comprendendo queste tecniche di fusione e le loro implicazioni, è possibile strutturare in modo efficace il codice TypeScript, migliorando la riutilizzabilità e la manutenibilità pur mantenendo la sicurezza dei tipi.

Raggruppamenti e trasformazioni in TypeScript

Non tutti i browser supportano il JavaScript più recente utilizzato da TypeScript. Quindi è possibile utilizzare il compilatore TypeScript, o tsc, per convertire il codice TypeScript (.ts) in JavaScript convenzionale (.js) compatibile universalmente con tutti i browser. tsc traduce elementi specifici di TypeScript come tipi e classi in codice JavaScript che i browser possono interpretare.

Per eseguire file TypeScript, tsc è il tuo punto di riferimento. È possibile installare tsc tramite npm e quindi trasformare i file .ts in file .js. Per utilizzare tsc, basta specificare il nome del file TypeScript prima del comando tsc. Ad esempio, se si ha un file chiamato app.ts, è possibile eseguirlo digitando:

tsc app.ts

Webpack o Parcel vengono spesso impiegati per distribuire codice TypeScript sui browser. Questi strumenti raggruppano tutti i file JavaScript, compresi quelli da TypeScript, per un migliore rendimento e una più facile implementazione del sito web. Ottimizzano inoltre il caricamento del codice riducendone le dimensioni e migliorando la velocità del browser.

Costruire un codice migliore con TypeScript

Abbracciare TypeScript come sviluppatore JavaScript apre possibilità per scrivere un codice più robusto e mantenibile. Capendo i concetti di base delineati in questa guida, puoi sfruttare il sistema di tipizzazione statica di TypeScript per individuare errori in fase di sviluppo, riducendo così bug e agevolando la manutenzione del codice.

Usando TypeScript, gli sviluppatori JavaScript possono migliorare la qualità e la produttività del proprio codice. Continuando ad esplorare e praticare con TypeScript, scoprirai funzionalità e caratteristiche ancora più potenti.

Continua a spingere i tuoi limiti e immergiti sempre più nel mondo di TypeScript. 😉