Tipi di utilità in TypeScript

Tipi di utilità in TypeScript

Questo articolo spiega i tipi di utilità in TypeScript.

YouTube Video

Tipi di utilità in TypeScript

I tipi di utilità di TypeScript sono strumenti pratici per creare nuovi tipi basati su tipi esistenti. Ciò consente definizioni di tipo più flessibili e aumenta la riutilizzabilità del codice. Qui spiegheremo in dettaglio i tipi di utilità più comunemente usati e discuteremo come utilizzare ciascuno con esempi di codice.

Partial<T>

Partial<T> rende tutte le proprietà di un tipo oggetto opzionali (consentendo undefined). È utile quando vuoi utilizzare solo alcune delle proprietà che il tipo originale possiede.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7function updateUser(user: Partial<User>) {
 8  console.log(user);
 9}
10
11updateUser({ name: "Alice" }); // Updates only 'name'

Spiegazione:

Nell'esempio sopra, l'uso di Partial<User> rende tutte le proprietà del tipo User opzionali. Pertanto, nella funzione updateUser, puoi passare solo un sottoinsieme delle proprietà.

Required<T>

Required<T> rende tutte le proprietà, incluse quelle opzionali, obbligatorie. Si usa quando vuoi convertire proprietà opzionali in obbligatorie.

 1interface User {
 2  id: number;
 3  name?: string;
 4  age?: number;
 5}
 6
 7function createUser(user: Required<User>) {
 8  console.log(user);
 9}
10
11// createUser({ id: 1 }); // Error: 'name' and 'age' are required
12createUser({ id: 1, name: "Alice", age: 25 });

Spiegazione:

Usando Required<User>, proprietà come name e age sono trattate come obbligatorie.

Readonly<T>

Readonly<T> rende tutte le proprietà di un oggetto di sola lettura. Ciò impedisce che i valori dell'oggetto vengano modificati.

 1interface User {
 2  id: number;
 3  name: string;
 4}
 5
 6const user: Readonly<User> = {
 7  id: 1,
 8  name: "Alice"
 9};
10
11// user.id = 2; // Error: 'id' is read-only
12console.log(user);

Spiegazione:

Usando Readonly<T>, puoi proteggere le proprietà di un oggetto da modifiche. È efficace quando vuoi impedire che i dati vengano modificati accidentalmente durante lo sviluppo.

Record<K, T>

Record<K, T> crea un tipo mappa con tipi di chiave e valore specificati. K è il tipo per le chiavi (come string o number), e T è il tipo per i valori.

 1type Roles = "admin" | "user" | "guest";
 2interface Permissions {
 3  read: boolean;
 4  write: boolean;
 5}
 6
 7const rolePermissions: Record<Roles, Permissions> = {
 8  admin: { read: true, write: true },
 9  user: { read: true, write: false },
10  guest: { read: false, write: false },
11};
12
13console.log(rolePermissions);

Spiegazione:

Record<K, T> è utile quando vuoi definire coppie chiave-valore. Nell'esempio sopra, i permessi sono definiti in base ai ruoli utente.

Pick<T, K>

Pick<T, K> estrae solo le proprietà specificate da un tipo oggetto. Puoi creare un nuovo tipo estraendo solo le proprietà necessarie.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5}
 6
 7type UserSummary = Pick<User, "id" | "name">;
 8
 9const summary: UserSummary = {
10  id: 1,
11  name: "Alice"
12};
13
14console.log(summary);

Spiegazione:

Usando Pick<T, K>, puoi estrarre proprietà specifiche da un tipo oggetto e trattarle come un nuovo tipo. Ad esempio, solo id e name vengono estratti nell'esempio sopra.

Omit<T, K>

Omit<T, K> esclude proprietà specificate da un tipo oggetto. Questa è l'operazione opposta a Pick.

 1interface User {
 2  id: number;
 3  name: string;
 4  age: number;
 5  email: string;
 6}
 7
 8type UserWithoutEmail = Omit<User, "email">;
 9
10const userWithoutEmail: UserWithoutEmail = {
11  id: 1,
12  name: "Alice",
13  age: 25
14};
15
16console.log(userWithoutEmail);

Spiegazione:

Usando Omit<T, K>, è possibile creare un nuovo tipo escludendo proprietà specificate. Nell'esempio sopra, la proprietà email viene esclusa.

Exclude<T, U>

Exclude<T, U> crea un nuovo tipo rimuovendo il tipo U dal tipo unione T. Viene utilizzato quando si desidera rimuovere un tipo specifico.

1type Status = "active" | "inactive" | "pending";
2type ExcludedStatus = Exclude<Status, "pending">;
3
4const status: ExcludedStatus = "active"; // "pending" is excluded, so it cannot be chosen
5console.log(status);

Spiegazione:

Usando Exclude<T, U>, è possibile rimuovere tipi non necessari da un tipo unione. Nell'esempio sopra, poiché "pending" viene escluso, possono essere selezionati solo "active" o "inactive".

Extract<T, U>

Extract<T, U> estrae le porzioni che corrispondono al tipo U all'interno del tipo unione T. È utile quando si desidera estrarre solo un tipo specifico.

1type Status = "active" | "inactive" | "pending";
2type ActiveStatus = Extract<Status, "active" | "pending">;
3
4const status: ActiveStatus = "active"; // "inactive" cannot be chosen
5console.log(status);

Spiegazione:

Extract<T, U> esegue l'operazione opposta a Exclude. Nell'esempio sopra, possono essere selezionati solo "active" e "pending".

NonNullable<T>

NonNullable<T> crea un tipo con null e undefined esclusi. È utile quando si desidera escludere questi valori dai tipi opzionali.

1type UserName = string | null | undefined;
2type ValidUserName = NonNullable<UserName>;
3
4const name: ValidUserName = "Alice"; // null and undefined cannot be chosen
5console.log(name);

Spiegazione:

NonNullable<T> esclude null e undefined da un tipo che li contiene. Questo è utile quando si vuole garantire che un valore esista sicuramente.

Conclusione

I tipi di utilità di TypeScript sono strumenti potenti per rendere le definizioni di tipo più concise e flessibili. Capire e utilizzare adeguatamente tipi di utilità di base come Partial, Required, Readonly, Record, ecc., può migliorare la riutilizzabilità e la manutenibilità del codice. Padroneggiare questi tipi consente di creare definizioni di tipo più robuste e sicure, favorendo uno sviluppo efficiente.

L'operatore keyof di TypeScript

L'operatore keyof di TypeScript viene utilizzato per ottenere tutti i nomi delle proprietà di un tipo oggetto. Utilizzando questo operatore, è possibile ottenere le chiavi di un tipo oggetto come tipo unione. Questo è estremamente utile per scrivere codice sicuro per i tipi.

Uso di base

1interface Person {
2    name: string;
3    age: number;
4    email: string;
5}
6
7// Use keyof to get the property names of Person
8type PersonKeys = keyof Person; // "name" | "age" | "email"

Esempio di utilizzo

  1. Utilizzo negli Argomenti delle Funzioni

    È possibile utilizzare keyof per definire una funzione con tipi basati su proprietà specifiche di un oggetto.

1function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
2    return obj[key];
3}
4
5const person: Person = { name: "Alice", age: 30, email: "alice@example.com" };
6const name = getProperty(person, "name"); // type is string
7const age = getProperty(person, "age");   // type is number
  1. Miglioramento dei Vincoli di Tipo

    Utilizzando keyof, è possibile garantire che le chiavi passate a una funzione vengano validate durante la fase di compilazione.

1// Passing an invalid property name results in an error
2const invalid = getProperty(person, "invalidKey"); // Error

Riepilogo

  • L'operatore keyof viene utilizzato per recuperare tutti i nomi delle proprietà di un tipo oggetto.
  • È possibile ottenere i nomi delle proprietà come tipo unione, ottenendo codice sicuro per i tipi.
  • Utilizzandolo negli argomenti di funzione, è possibile limitare la funzione ad accettare solo nomi di proprietà validi.

In questo modo, l'operatore keyof migliora la sicurezza dei tipi in TypeScript e ti aiuta a scrivere codice più robusto.

Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.

YouTube Video