In TypeScript possiamo specificare con precisione la struttura degli oggetti, indicando quali proprietà possono contenere e quale tipo di valore deve avere ciascuna di esse.
Questa possibilità permette a TypeScript di controllare gli oggetti durante la compilazione e di fornire un autocompletamento più preciso nell'editor.
Possiamo definire direttamente la struttura dell'oggetto attraverso una dichiarazione esplicita del tipo, senza dover creare un tipo separato.
In TypeScript, possiamo definire un oggetto con la seguente sintassi di base:
{
proprietà1: tipo1;
proprietà2: tipo2;
}Ad esempio, possiamo definire un oggetto persona:
const persona: {
nome: string;
eta: number;
} = {
nome: "Andrea",
eta: 30
};Abbiamo quindi specificato che persona deve essere un oggetto con:
nome di tipo string. eta di tipo number. Se proviamo ad assegnare un valore di tipo diverso, TypeScript segnala un errore perché eta deve essere un number:
const persona: {
nome: string;
eta: number;
} = {
nome: "Andrea",
eta: "30"
};Quando definiamo una proprietà senza utilizzare altri modificatori, questa è obbligatoria.
Per esempio:
const persona: {
nome: string;
eta: number;
} = {
nome: "Andrea"
};Il codice genera un errore perché manca la proprietà eta.
Allo stesso modo, non possiamo aggiungere arbitrariamente proprietà che non fanno parte della struttura dichiarata:
const persona: {
nome: string;
eta: number;
} = {
nome: "Andrea",
eta: 30,
email: "[email protected]"
};TypeScript segnala un errore perché email non è prevista nella struttura dell'oggetto. Questo controllo permette di individuare facilmente proprietà mancanti o scritte in modo errato.
Non tutte le proprietà devono necessariamente essere presenti. Possiamo rendere una proprietà opzionale utilizzando ? dopo il suo nome, come per le tuple.
Ad esempio:
const persona: {
nome: string;
eta?: number;
} = {
nome: "Andrea"
};In questo caso nome è obbligatoria, mentre eta può essere omessa.
Se la proprietà viene specificata, deve comunque rispettare il tipo indicato:
const persona: {
nome: string;
eta?: number;
} = {
nome: "Andrea",
eta: "30"
};In questo caso, TypeScript genera un errore perché eta, quando presente, deve essere un number.
Per leggere il valore di una proprietà di un oggetto, possiamo usare la sintassi oggetto.proprietà.
Ad esempio:
const persona: {
nome: string;
eta: number;
} = {
nome: "Andrea",
eta: 30
};
console.log(persona.nome);Quando una proprietà è opzionale, TypeScript considera anche la possibilità che il suo valore non sia presente. Per esempio:
const persona: {
nome: string;
eta?: number;
} = {
nome: "Marco"
};
console.log(persona.eta);Il valore di persona.eta può essere un number oppure undefined.
Possiamo impedire che una proprietà venga modificata dopo la creazione dell'oggetto utilizzando il modificatore readonly.
Per esempio:
const persona: {
readonly id: number;
nome: string;
} = {
id: 1,
nome: "Andrea"
};Possiamo modificare nome, ma non id:
persona.nome = "Luca";
persona.id = 2; // ErroreFinora abbiamo definito in anticipo tutte le proprietà che un oggetto può contenere.
In alcuni casi, però, abbiamo bisogno di gestire oggetti con proprietà dinamiche, cioè proprietà in cui i valori non si conoscono in anticipo.
Per esempio, potremmo avere un oggetto che contiene una serie di punteggi:
const punteggi = {
Andrea: 10,
Luca: 8,
Anna: 9
};Se vogliamo permettere un numero arbitrario di proprietà, possiamo utilizzare una firma dell'indice (in inglese, index signature).
La sintassi è:
{
[key: string]: tipo;
}Per esempio:
const punteggi: {
[key: string]: number;
} = {
Andrea: 10,
Luca: 8,
Anna: 9
};In questo caso [key: string] indica che le proprietà possono avere nomi di tipo string, mentre il valore associato deve essere un number.
Con le firme dell'indice, possiamo aggiungere nuove proprietà dinamicamente:
const punteggi: {
[key: string]: number;
} = {};
punteggi["Paolo"] = 7;
punteggi["Sara"] = 10;Il valore inserito dinamicamente deve comunque rispettare il tipo indicato:
const punteggi: {
[key: string]: number;
} = {};
punteggi["Andrea"] = "10"; // ErroreIl codice nell'esempio genera un errore perché la firma dell'indice stabilisce che tutti i valori devono essere number.
Possiamo anche accedere alle proprietà utilizzando la notazione con parentesi:
console.log(punteggi["Andrea"]);Una firma dell'indice può essere utilizzata anche insieme a proprietà specifiche.
Ad esempio:
const utente: {
nome: string;
[key: string]: string;
} = {
nome: "Andrea",
città: "Milano",
paese: "Italia"
};In questo caso nome è una proprietà definita esplicitamente, mentre le altre proprietà possono essere dinamiche.
È però necessario che il tipo della proprietà definita sia compatibile con quello della firma. Per esempio, questa struttura non è valida:
const utente: {
nome: string;
[key: string]: number;
} = {
nome: "Andrea" // Errore
};Nell'esempio, nome è infatti una string, mentre la firma dell'indice stabilisce che i valori devono essere number.