TypeScript - Tipi Mappati: Una Guida per Principianti
Ciao là, futuri maghi di TypeScript! Oggi ci imbarcheremo in un viaggio emozionante nel mondo dei Tipi Mappati. Non preoccupatevi se siete nuovi alla programmazione - sarò il vostro guida amichevole, e procederemo passo per passo. Alla fine di questo tutorial, mapperete i tipi come un professionista!
Cos'è un Tipo Mappato?
Prima di immergerci, capiamo cos'è un Tipo Mappato. Immagina di avere una scatola di cioccolatini misti e di voler creare una nuova scatola dove ogni cioccolatino è avvolto in foglia d'oro. Questo è essenzialmente ciò che fanno i Tipi Mappati in TypeScript - prendono un tipo esistente e lo trasformano in un nuovo tipo basato su un insieme di regole.
Tipi Mappati Predefiniti
TypeScript viene con alcuni Tipi Mappati predefiniti che sono super utili. Esaminiamoli uno per uno:
1. Partial<T>
Il tipo Partial<T>
rende tutte le proprietà di T
opzionali. È come trasformare una ricetta rigorosa in una flessibile dove puoi saltare alcuni ingredienti.
interface Recipe {
name: string;
ingredients: string[];
cookingTime: number;
}
type FlexibleRecipe = Partial<Recipe>;
// Ora possiamo creare una ricetta senza tutte le proprietà
const quickSnack: FlexibleRecipe = {
name: "Toast",
// Possiamo saltare ingredients e cookingTime
};
In questo esempio, FlexibleRecipe
ci permette di creare una ricetta senza specificare tutte le proprietà. È perfetto quando vuoi aggiornare solo una parte di un oggetto.
2. Required<T>
Required<T>
è l'opposto di Partial<T>
. Rende tutte le proprietà obbligatorie, anche se erano opzionali nel tipo originale.
interface UserProfile {
name: string;
age?: number;
email?: string;
}
type CompleteUserProfile = Required<UserProfile>;
// Ora dobbiamo fornire tutte le proprietà
const user: CompleteUserProfile = {
name: "Alice",
age: 30,
email: "[email protected]"
};
Qui, CompleteUserProfile
assicura che forniamo tutte le proprietà, inclusi age
e email
che erano opzionali nel UserProfile
originale.
3. Readonly<T>
Readonly<T>
rende tutte le proprietà di T
di sola lettura. È come mettere il tuo tipo in una vetrina - puoi guardare, ma non puoi toccare!
interface Toy {
name: string;
price: number;
}
type CollectibleToy = Readonly<Toy>;
const actionFigure: CollectibleToy = {
name: "Supereroe",
price: 19.99
};
// Questo causerà un errore
// actionFigure.price = 29.99;
In questo esempio, una volta creato il nostro actionFigure
, non possiamo modificare le sue proprietà. È ottimo per creare oggetti immutabili.
4. Pick<T, K>
Pick<T, K>
crea un nuovo tipo selezionando solo le proprietà specificate K
da T
. È come scegliere i tuoi feature preferiti da un tipo.
interface Smartphone {
brand: string;
model: string;
year: number;
color: string;
price: number;
}
type BasicPhoneInfo = Pick<Smartphone, 'brand' | 'model'>;
const myPhone: BasicPhoneInfo = {
brand: "TechBrand",
model: "X2000"
};
Qui, BasicPhoneInfo
include solo le proprietà brand
e model
da Smartphone
, lasciando fuori le altre.
5. Omit<T, K>
Omit<T, K>
è l'opposto di Pick<T, K>
. Crea un nuovo tipo rimuovendo le proprietà specificate K
da T
.
interface Book {
title: string;
author: string;
pages: number;
isbn: string;
}
type BookPreview = Omit<Book, 'pages' | 'isbn'>;
const preview: BookPreview = {
title: "Avventure TypeScript",
author: "Mago del Codice"
};
In questo caso, BookPreview
include tutte le proprietà di Book
tranne pages
e isbn
.
Esempi di Utilizzo dei Tipi Mappati
Ora che abbiamo visto i Tipi Mappati predefiniti, esaminiamo alcuni esempi pratici di come possiamo usarli in scenari reali.
Esempio 1: Creazione di uno Stato di Modulo
Immagina di essere in procinto di costruire un modulo e di voler tenere traccia di quali campi sono stati modificati:
interface LoginForm {
username: string;
password: string;
rememberMe: boolean;
}
type FormTouched = { [K in keyof LoginForm]: boolean };
const touchedFields: FormTouched = {
username: true,
password: false,
rememberMe: true
};
Qui, abbiamo creato un tipo FormTouched
che ha le stesse chiavi di LoginForm
, ma tutti i valori sono booleani che indicano se il campo è stato toccato.
Esempio 2: Wrapper di Risposta API
Supponiamo di avere un'API che restituisce diversi tipi di dati e di voler incapsulare ogni risposta in un formato standard:
interface ApiResponse<T> {
data: T;
status: 'success' | 'error';
timestamp: number;
}
type UserData = { id: number; name: string; email: string };
type ProductData = { id: number; name: string; price: number };
const userResponse: ApiResponse<UserData> = {
data: { id: 1, name: "John Doe", email: "[email protected]" },
status: 'success',
timestamp: Date.now()
};
const productResponse: ApiResponse<ProductData> = {
data: { id: 101, name: "Laptop", price: 999.99 },
status: 'success',
timestamp: Date.now()
};
Questo esempio mostra come possiamo usare i generici con i Tipi Mappati per creare strutture di tipo flessibili e riutilizzabili.
Creazione di Tipi Mappati Personalizzati
Ora, mettiamo in pratica le nostre abilità di TypeScript e creiamo alcuni Tipi Mappati personalizzati!
Tipo Personalizzato 1: Nullable
Creiamo un tipo che rende tutte le proprietà nullable:
type Nullable<T> = { [K in keyof T]: T[K] | null };
interface Person {
name: string;
age: number;
}
type NullablePerson = Nullable<Person>;
const maybePerson: NullablePerson = {
name: "Jane",
age: null // Questo è ora valido
};
Il nostro tipo Nullable<T>
permette a qualsiasi proprietà di essere il suo tipo originale o null
.
Tipo Personalizzato 2: Freezable
Creiamo un tipo che aggiunge un metodo freeze
a un oggetto:
type Freezable<T> = T & { freeze(): Readonly<T> };
interface Config {
theme: string;
fontSize: number;
}
function makeFreezable<T>(obj: T): Freezable<T> {
return {
...obj,
freeze() {
return Object.freeze({ ...this }) as Readonly<T>;
}
};
}
const config = makeFreezable<Config>({
theme: "dark",
fontSize: 14
});
const frozenConfig = config.freeze();
// frozenConfig.theme = "light"; // Questo causerebbe un errore
Questo tipo personalizzato aggiunge un metodo freeze
a qualsiasi oggetto, permettendoci di creare una versione immutabile di esso.
Conclusione
Wow, abbiamo coperto molto terreno oggi! Dai Tipi Mappati predefiniti alla creazione dei nostri tipi personalizzati, avete visto quanto TypeScript possa essere potente e flessibile. I Tipi Mappati sono come bacchette magiche nel vostro toolkit TypeScript - vi permettono di trasformare e manipolare i tipi in modi incredibilmente utili.
Ricordate, la chiave per padroneggiare i Tipi Mappati è la pratica. Prova a crearne alcuni, esperimenta con diverse combinazioni, e presto scriverete codice TypeScript che non è solo funzionale, ma anche elegante e sicuro.
Continuate a codificare, continuate a imparare, e, soprattutto, divertitevi con TypeScript!
Credits: Image by storyset