Sfruttare i Tipi di Utilità in TypeScript

TypeScript offre numerosi tipi di utilità che ti permettono di manipolare i tipi in modo dinamico e pratico. Che sia per rendere le proprietà opzionali, immutabili o per filtrare certi campi di un tipo, queste utilità possono aiutarti a scrivere codice più pulito, più sicuro e più leggibile.

In questo articolo, scoprirai alcuni dei tipi di utilità più comunemente utilizzati in TypeScript, con esempi concreti per mostrarti come e quando utilizzarli.

1. Partial<T>

Il tipo di utilità Partial<T> trasforma tutte le proprietà di un tipo T in proprietà opzionali. Questo è particolarmente utile quando lavori con oggetti dove non tutte le proprietà sono sempre necessarie.

Esempio

Immaginiamo un tipo User con proprietà obbligatorie:

typescript
1type User = {
2 id: number;
3 name: string;
4 email: string;
5};

Se desideri creare una funzione che aggiorna un utente, ma che necessita solo di un sottoinsieme di queste proprietà, puoi utilizzare Partial<User>:

typescript
1function updateUser(user: User, updates: Partial<User>) {
2 return { ...user, ...updates };
3}
4
5// Utilizzo
6const user: User = { id: 1, name: 'Alice', email: 'alice@example.com' };
7const updatedUser = updateUser(user, { name: 'Alicia' });

Grazie a Partial<User>, ora puoi aggiornare solo alcune proprietà senza dover fornire tutte le altre.

2. Readonly<T>

Readonly<T> rende tutte le proprietà di un tipo T immutabili. Questo significa che una volta che l'oggetto è creato, non puoi più modificare le sue proprietà, il che è ideale per gli oggetti costanti.

Esempio

typescript
1type Config = {
2 apiEndpoint: string;
3 timeout: number;
4};
5
6const config: Readonly<Config> = {
7 apiEndpoint: 'https://api.example.com',
8 timeout: 5000,
9};
10
11// Errore: Impossibile assegnare a 'timeout' perché è una proprietà di sola lettura
12config.timeout = 3000;

Utilizzando Readonly<Config>, ti assicuri che config rimanga immutabile durante l'esecuzione.

3. Pick<T, K>

Il tipo di utilità Pick<T, K> crea un nuovo tipo selezionando solo alcune proprietà di un tipo T. Questo è utile quando desideri creare una sottoparte di un tipo esistente.

Esempio

typescript
1type User = {
2 id: number;
3 name: string;
4 email: string;
5 address: string;
6};
7
8type UserSummary = Pick<User, 'id' | 'name'>;
9
10const userSummary: UserSummary = {
11 id: 1,
12 name: 'Alice',
13};
14
15// Errore: La proprietà 'email' non esiste sul tipo 'UserSummary'
16userSummary.email = 'alice@example.com';

Con Pick<User, "id" | "name">, crei un tipo UserSummary che contiene solo le proprietà id e name.

4. Omit<T, K>

Al contrario, Omit<T, K> crea un nuovo tipo escludendo alcune proprietà da un tipo T. È l'opposto di Pick.

Esempio

typescript
1type UserWithoutAddress = Omit<User, 'address'>;
2
3const userWithoutAddress: UserWithoutAddress = {
4 id: 1,
5 name: 'Alice',
6 email: 'alice@example.com',
7};
8
9// Errore: La proprietà 'address' non esiste sul tipo 'UserWithoutAddress'
10userWithoutAddress.address = '123 Main St';

In questo esempio, UserWithoutAddress contiene tutte le proprietà di User, tranne address.

5. Record<K, T>

Record<K, T> è utilizzato per creare un tipo di oggetto dove le chiavi K sono di un tipo specifico, e i valori sono del tipo T. Questo è utile per creare oggetti associativi, come dizionari o mappature.

Esempio

Supponiamo che tu voglia creare un oggetto che associa ruoli utente a permessi di accesso:

typescript
1type Role = 'admin' | 'user' | 'guest';
2type Permissions = 'read' | 'write' | 'delete';
3
4const rolePermissions: Record<Role, Permissions[]> = {
5 admin: ['read', 'write', 'delete'],
6 user: ['read', 'write'],
7 guest: ['read'],
8};

In questo esempio, Record<Role, Permissions[]> assicura che l'oggetto rolePermissions contenga tutte le chiavi admin, user, e guest, con valori di tipo Permissions[].

6. Exclude<T, U>

Exclude<T, U> permette di creare un tipo escludendo certi tipi da un altro tipo. È utile per filtrare tipi specifici da un Union Type.

Esempio

typescript
1type Status = 'active' | 'inactive' | 'suspended';
2
3type ActiveStatus = Exclude<Status, 'suspended'>;
4
5const status: ActiveStatus = 'active'; // Valido
6const anotherStatus: ActiveStatus = 'suspended'; // Errore

Utilizzando Exclude<Status, "suspended">, crei un tipo ActiveStatus che non può essere "suspended".

Conclusione

I tipi di utilità di TypeScript ti permettono di esprimere tipi complessi in modo conciso e leggibile. Sfruttando Partial, Readonly, Pick, Omit, Record, e Exclude, puoi manipolare i tuoi tipi in modo dinamico e rispondere alle esigenze della tua applicazione senza appesantire il tuo codice.

Questi strumenti sono solo la punta dell'iceberg: TypeScript offre molti altri tipi di utilità avanzati. Prenditi il tempo di esplorare questi strumenti, e il tuo codice sarà più manutenibile, più sicuro e più facile da leggere.


Applicando questi suggerimenti, potrai manipolare i tuoi tipi in modo più efficace e scrivere codice TypeScript ancora più robusto. Buon coding!

Condividi questo articolo


Sébastien Timoner

Sébastien TIMONER

Lead Developer
Esperto in Sviluppo su Misura
Aix-en-Provence, France

Esperto nello sviluppo web e nella gestione di team tecnici, mi specializzo nella creazione e ottimizzazione di soluzioni digitali performanti. Grazie a una profonda padronanza di tecnologie moderne come React.js, Node.js, TypeScript e Symfony, garantisco il successo di progetti SaaS complessi, dalla progettazione alla messa in produzione, per aziende di diversi settori, all'interno di offroadLabs.

In offroadLabs, offro servizi di sviluppo su misura, combinando competenza tecnica e approccio collaborativo. Che si tratti di creare una soluzione SaaS innovativa, modernizzare un'applicazione esistente o accompagnare la crescita professionale di un team, mi impegno a fornire soluzioni robuste e performanti, adattate alle esigenze specifiche di ogni progetto.

Sono disponibile per incarichi intorno ad Aix-en-Provence o in full remote.