Pompei Tech
Guide · typescript

Generics

Generics

Immagina un archivista che deve riorganizzare una fila di scatoloni numerati in un archivio con scaffali etichettati per codice. Il procedimento che segue è sempre lo stesso, indipendentemente dal fatto che gli scatoloni contengano fatture, contratti o fotografie: prende ogni scatolone, legge il codice identificativo, lo colloca sullo scaffale con quell'etichetta. Il "procedimento di riorganizzazione" è generico — funziona con qualsiasi tipo di contenuto — ma l'archivista non perde mai traccia di cosa c'è dentro ogni scatolone: se erano fatture, restano fatture anche una volta archiviate.

I generics ci permettono di parametrizzare i tipi, il che sblocca una grande opportunità di riutilizzare i tipi in modo ampio in un progetto TypeScript — esattamente come la procedura di archiviazione del nostro archivista, che funziona con qualsiasi tipo di documento senza mai perdere l'informazione su cosa contiene ogni scatolone.

Questo è un concetto piuttosto astratto, quindi partiamo da un esempio pratico concreto.

Un caso d'uso motivante

In un capitolo precedente, abbiamo parlato del concetto di strutture dati a dizionario, che potevamo tipizzare usando le index signature:

ts
const numeriTelefono: {
  [k: string]: {
    idCliente: string;
    prefisso: string;
    numero: string;
  };
} = {};

numeriTelefono.casa;
numeriTelefono.lavoro;
numeriTelefono.fax;
numeriTelefono.cellulare;

Diamo per assodato che a volte è più comodo organizzare le collezioni come dizionari chiave-valore, e altre volte è più comodo usare array o liste.

Sarebbe utile avere una specie di utility che ci permetta di convertire una "lista di cose" in un "dizionario di cose" — esattamente come il nostro archivista che converte una fila di scatoloni numerati in uno scaffale organizzato per codice.

Prendiamo quindi questo array di oggetti come punto di partenza:

ts
const listaNumeri = [
  { idCliente: "0001", prefisso: "321", numero: "123-4566" },
  { idCliente: "0002", prefisso: "174", numero: "142-3626" },
  { idCliente: "0003", prefisso: "192", numero: "012-7190" },
  { idCliente: "0005", prefisso: "402", numero: "652-5782" },
  { idCliente: "0004", prefisso: "301", numero: "184-8501" },
];

... e questo è quello che vogliamo ottenere alla fine:

ts
const dizionarioNumeri = {
  "0001": { idCliente: "0001", prefisso: "321", numero: "123-4566" },
  "0002": { idCliente: "0002", prefisso: "174", numero: "142-3626" },
  /*... e così via */
};

Alla fine, speriamo di arrivare a una soluzione che funzioni per qualsiasi lista vogliamo trasformare nell'equivalente dizionario — non solo per questo caso specifico.

Ci servirà prima di tutto un modo per produrre la "chiave" per ogni oggetto che incontriamo nell'array listaNumeri. Per restare flessibili, progetteremo la nostra funzione in modo che chiunque chieda la conversione da lista a dizionario debba anche fornire una funzione che possiamo usare per ottenere una "chiave" da ogni elemento della lista.

Forse la firma della nostra funzione assomiglierebbe a questa:

ts
interface InfoTelefono {
  InfoTelefono.idCliente: stringidCliente: string;
  InfoTelefono.prefisso: stringprefisso: string;
  InfoTelefono.numero: stringnumero: string;
}

function 
function listaADizionario(lista: InfoTelefono[], generaId: (arg: InfoTelefono) => string): {
    [k: string]: InfoTelefono;
}
listaADizionario
(
lista: InfoTelefono[]lista: InfoTelefono[], // prende la lista come argomento generaId: (arg: InfoTelefono) => stringgeneraId: (arg: InfoTelefonoarg: InfoTelefono) => string, // una callback per ottenere gli id ): { [k: string]: InfoTelefono } {
A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
// restituisce un dizionario }

Ovviamente vediamo un messaggio d'errore per come stanno le cose ora, perché non abbiamo ancora implementato la funzione.

Non è troppo difficile da implementare. Costruiamo subito una soluzione molto specifica con un forEach — che rifattorizzeremo e generalizzeremo nel prossimo passaggio.

ts
interface InfoTelefono {
  InfoTelefono.idCliente: stringidCliente: string;
  InfoTelefono.prefisso: stringprefisso: string;
  InfoTelefono.numero: stringnumero: string;
}

function 
function listaADizionario(lista: InfoTelefono[], generaId: (arg: InfoTelefono) => string): {
    [k: string]: InfoTelefono;
}
listaADizionario
(
lista: InfoTelefono[]lista: InfoTelefono[], generaId: (arg: InfoTelefono) => stringgeneraId: (arg: InfoTelefonoarg: InfoTelefono) => string, ): { [k: stringk: string]: InfoTelefono } { // crea un dizionario vuoto const
const dizionario: {
    [k: string]: InfoTelefono;
}
dizionario
: { [k: stringk: string]: InfoTelefono } = {};
// scorri l'array lista: InfoTelefono[]lista.Array<InfoTelefono>.forEach(callbackfn: (value: InfoTelefono, index: number, array: InfoTelefono[]) => void, thisArg?: any): void
Performs the specified action for each element in an array.
@paramcallbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
forEach
((elemento: InfoTelefonoelemento) => {
const const chiaveDizionario: stringchiaveDizionario = generaId: (arg: InfoTelefono) => stringgeneraId(elemento: InfoTelefonoelemento);
const dizionario: {
    [k: string]: InfoTelefono;
}
dizionario
[const chiaveDizionario: stringchiaveDizionario] = elemento: InfoTelefonoelemento; // memorizza l'elemento sotto quella chiave
}); // restituisci il dizionario return
const dizionario: {
    [k: string]: InfoTelefono;
}
dizionario
;
} const
const listaNumeri: {
    idCliente: string;
    prefisso: string;
    numero: string;
}[]
listaNumeri
= [
{ idCliente: stringidCliente: "0001", prefisso: stringprefisso: "321", numero: stringnumero: "123-4566" }, { idCliente: stringidCliente: "0002", prefisso: stringprefisso: "174", numero: stringnumero: "142-3626" }, ]; const
const risultato: {
    [k: string]: InfoTelefono;
}
risultato
=
function listaADizionario(lista: InfoTelefono[], generaId: (arg: InfoTelefono) => string): {
    [k: string]: InfoTelefono;
}
listaADizionario
(
const listaNumeri: {
    idCliente: string;
    prefisso: string;
    numero: string;
}[]
listaNumeri
, (item: InfoTelefonoitem) => item: InfoTelefonoitem.InfoTelefono.idCliente: stringidCliente);
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(
const risultato: {
    [k: string]: InfoTelefono;
}
risultato
);

Prova questa soluzione nel TypeScript Playground: dovresti vedere che funziona per il nostro esempio specifico.

Ora proviamo a generalizzarla, in modo che funzioni per liste e dizionari del nostro tipo InfoTelefono, ma anche per tanti altri tipi. Che ne dici se sostituissimo ogni occorrenza di InfoTelefono con any?

ts
function 
function listaADizionario(lista: any[], generaId: (arg: any) => string): {
    [k: string]: any;
}
listaADizionario
(
lista: any[]lista: any[], generaId: (arg: any) => stringgeneraId: (arg: anyarg: any) => string, ): { [k: stringk: string]: any } { // niente cambia nel codice qui sotto const
const dizionario: {
    [k: string]: any;
}
dizionario
: { [k: stringk: string]: any } = {};
lista: any[]lista.Array<any>.forEach(callbackfn: (value: any, index: number, array: any[]) => void, thisArg?: any): void
Performs the specified action for each element in an array.
@paramcallbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
forEach
((elemento: anyelemento) => {
const const chiaveDizionario: stringchiaveDizionario = generaId: (arg: any) => stringgeneraId(elemento: anyelemento);
const dizionario: {
    [k: string]: any;
}
dizionario
[const chiaveDizionario: stringchiaveDizionario] = elemento: anyelemento;
}); return
const dizionario: {
    [k: string]: any;
}
dizionario
;
} const
const dizionario: {
    [k: string]: any;
}
dizionario
=
function listaADizionario(lista: any[], generaId: (arg: any) => string): {
    [k: string]: any;
}
listaADizionario
(
[{ nome: stringnome: "Mike" }, { nome: stringnome: "Mark" }], (item: anyitem) => item: anyitem.nome, ); var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(
const dizionario: {
    [k: string]: any;
}
dizionario
);
// nessun errore di compilazione qui, ma è un disastro annunciato a runtime!
const dizionario: {
    [k: string]: any;
}
dizionario
.
__type[string]: any
Mike
.non.dovrei.poter.fare.questo.NOOOOOOO;

Ok, questo funziona a runtime se lo provi nel Playground, ma ogni elemento nel nostro dizionario è un any. Diventando più flessibili, e cercando di gestire una varietà di elementi diversi, abbiamo di fatto perso tutte le informazioni di tipo utili che avevamo.

Quello che ci serve qui è un meccanismo per definire una relazione tra il tipo della cosa che ci viene passata, e il tipo della cosa che restituiremo. Questo è esattamente ciò di cui si occupano i Generics.

Definire un parametro di tipo

I parametri di tipo si possono pensare come "argomenti di funzione, ma per i tipi".

Le funzioni possono restituire valori diversi, a seconda degli argomenti che passi loro.

I generics possono cambiare il loro tipo, a seconda dei parametri di tipo che usi insieme a loro.

La firma della nostra funzione includerà ora un parametro di tipo T:

ts
function listaADizionario<T>(
  lista: T[],
  generaId: (arg: T) => string,
): { [k: string]: T } {
  const dizionario: { [k: string]: T } = {};
  return dizionario;
}

Vediamo cosa significa questo codice.

Il parametro di tipo, e il suo uso per fornire il tipo di un argomento

  • <T> a destra di listaADizionario — significa che il tipo di questa funzione è ora parametrizzato in termini di un parametro di tipo T (che può cambiare a ogni singolo utilizzo).
  • lista: T[] come primo argomento — significa che accettiamo una lista di T.
    • TypeScript inferirà cos'è T in base al singolo utilizzo, a seconda del tipo di array che passiamo. Se usiamo uno string[], T sarà string; se usiamo un number[], T sarà number.

Prova a convincerti di queste prime due idee con questo esempio molto più semplice (e più inutile):

ts
function avvolgiInArray<T>(arg: T): [T] {
  return [arg];
}

Nota come, nei tre esempi di avvolgiInArray qui sotto, il <T> che vediamo nella dichiarazione qui sopra viene sostituito da "il tipo della cosa che passiamo come argomento" — number, Date, e RegExp:

ts
function function avvolgiInArray<T>(arg: T): [T]avvolgiInArray<function (type parameter) T in avvolgiInArray<T>(arg: T): [T]T>(arg: Targ: function (type parameter) T in avvolgiInArray<T>(arg: T): [T]T): [function (type parameter) T in avvolgiInArray<T>(arg: T): [T]T] {
  return [arg: Targ];
}

function avvolgiInArray<number>(arg: number): [number]
avvolgiInArray
(3);
function avvolgiInArray<Date>(arg: Date): [Date]
avvolgiInArray
(new
var Date: DateConstructor
new () => Date (+4 overloads)
Date
());
function avvolgiInArray<RegExp>(arg: RegExp): [RegExp]
avvolgiInArray
(new
var RegExp: RegExpConstructor
new (pattern: RegExp | string, flags?: string) => RegExp (+2 overloads)
RegExp
("/s/"));

Ok, torniamo all'esempio più significativo della nostra funzione listaADizionario:

ts
function listaADizionario<T>(
  lista: T[],
  generaId: (arg: T) => string, // anche questa usa T come argomento
): { [k: string]: T } {
  const dizionario: { [k: string]: T } = {};
  return dizionario;
}

generaId: (arg: T) => string è una callback che anch'essa usa T come argomento. Questo significa che...

  • Otteniamo i benefici del type checking, all'interno della funzione generaId.
  • Otteniamo un certo allineamento nel type checking tra l'array e la funzione generaId.
ts
function 
function listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
listaADizionario
<
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
>(
lista: T[]lista:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
[], // prende la lista come argomento
generaId: (arg: T) => stringgeneraId: (arg: Targ:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
) => string, // una callback per ottenere gli id
): { [k: stringk: string]:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
} {
const
const dizionario: {
    [k: string]: T;
}
dizionario
: { [k: stringk: string]:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
} = {};
return
const dizionario: {
    [k: string]: T;
}
dizionario
;
} // TypeScript sa che T è Date, dedotto dal tipo dell'array!
function listaADizionario<Date>(lista: Date[], generaId: (arg: Date) => string): {
    [k: string]: Date;
}
listaADizionario
(
[ new
var Date: DateConstructor
new (value: number | string | Date) => Date (+4 overloads)
Date
("10-01-2021"),
new
var Date: DateConstructor
new (value: number | string | Date) => Date (+4 overloads)
Date
("03-14-2021"),
new
var Date: DateConstructor
new (value: number | string | Date) => Date (+4 overloads)
Date
("06-03-2021"),
], (
arg: Date
arg
) => arg: Datearg.Date.toISOString(): string
Returns a date as a string value in ISO format.
toISOString
(),
);

Un'ultima cosa da esaminare: il tipo di ritorno. Nel modo in cui abbiamo definito questa funzione, un T[] verrà trasformato in { [k: string]: T } per qualsiasi T a nostra scelta.

Ora, mettiamo tutto insieme con l'esempio originale da cui siamo partiti:

ts
interface InfoTelefono {
  InfoTelefono.idCliente: stringidCliente: string;
  InfoTelefono.prefisso: stringprefisso: string;
  InfoTelefono.numero: stringnumero: string;
}

const 
const listaNumeri: {
    idCliente: string;
    prefisso: string;
    numero: string;
}[]
listaNumeri
= [
{ idCliente: stringidCliente: "0001", prefisso: stringprefisso: "321", numero: stringnumero: "123-4566" }, { idCliente: stringidCliente: "0002", prefisso: stringprefisso: "174", numero: stringnumero: "142-3626" }, ]; function
function listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
listaADizionario
<
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
>(
lista: T[]lista:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
[],
generaId: (arg: T) => stringgeneraId: (arg: Targ:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
) => string,
): { [k: stringk: string]:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
} {
const
const dizionario: {
    [k: string]: T;
}
dizionario
: { [k: stringk: string]:
function (type parameter) T in listaADizionario<T>(lista: T[], generaId: (arg: T) => string): {
    [k: string]: T;
}
T
} = {};
lista: T[]lista.Array<T>.forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void
Performs the specified action for each element in an array.
@paramcallbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
forEach
((elemento: Telemento) => {
const const chiaveDizionario: stringchiaveDizionario = generaId: (arg: T) => stringgeneraId(elemento: Telemento);
const dizionario: {
    [k: string]: T;
}
dizionario
[const chiaveDizionario: stringchiaveDizionario] = elemento: Telemento;
}); return
const dizionario: {
    [k: string]: T;
}
dizionario
;
} const
const dizionario1: {
    [k: string]: {
        nome: string;
    };
}
dizionario1
=
function listaADizionario<{
    nome: string;
}>(lista: {
    nome: string;
}[], generaId: (arg: {
    nome: string;
}) => string): {
    [k: string]: {
        nome: string;
    };
}
listaADizionario
([{ nome: stringnome: "Mike" }, { nome: stringnome: "Mark" }], (
item: {
    nome: string;
}
item
) =>
item: {
    nome: string;
}
item
.nome: stringnome);
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(
const dizionario1: {
    [k: string]: {
        nome: string;
    };
}
dizionario1
);
const dizionario1: {
    [k: string]: {
        nome: string;
    };
}
dizionario1
.
{
    nome: string;
}
Mike
;
const
const dizionario2: {
    [k: string]: {
        idCliente: string;
        prefisso: string;
        numero: string;
    };
}
dizionario2
=
function listaADizionario<{
    idCliente: string;
    prefisso: string;
    numero: string;
}>(lista: {
    idCliente: string;
    prefisso: string;
    numero: string;
}[], generaId: (arg: {
    idCliente: string;
    prefisso: string;
    numero: string;
}) => string): {
    [k: string]: {
        idCliente: string;
        prefisso: string;
        numero: string;
    };
}
listaADizionario
(
const listaNumeri: {
    idCliente: string;
    prefisso: string;
    numero: string;
}[]
listaNumeri
, (
p: {
    idCliente: string;
    prefisso: string;
    numero: string;
}
p
) =>
p: {
    idCliente: string;
    prefisso: string;
    numero: string;
}
p
.idCliente: stringidCliente);
const dizionario2: {
    [k: string]: {
        idCliente: string;
        prefisso: string;
        numero: string;
    };
}
dizionario2
.
{
    idCliente: string;
    prefisso: string;
    numero: string;
}
fax
;
var console: Console
The `console` module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers. The module exports two specific components: * A `Console` class with methods such as `console.log()`, `console.error()` and `console.warn()` that can be used to write to any Node.js stream. * A global `console` instance configured to write to [`process.stdout`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstdout) and [`process.stderr`](https://nodejs.org/docs/latest-v22.x/api/process.html#processstderr). The global `console` can be used without importing the `node:console` module. _**Warning**_: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the [`note on process I/O`](https://nodejs.org/docs/latest-v22.x/api/process.html#a-note-on-process-io) for more information. Example using the global `console`: ```js console.log('hello world'); // Prints: hello world, to stdout console.log('hello %s', 'world'); // Prints: hello world, to stdout console.error(new Error('Whoops, something bad happened')); // Prints error message and stack trace to stderr: // Error: Whoops, something bad happened // at [eval]:5:15 // at Script.runInThisContext (node:vm:132:18) // at Object.runInThisContext (node:vm:309:38) // at node:internal/process/execution:77:19 // at [eval]-wrapper:6:22 // at evalScript (node:internal/process/execution:76:60) // at node:internal/main/eval_string:23:3 const name = 'Will Robinson'; console.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to stderr ``` Example using the `Console` class: ```js const out = getStreamSomehow(); const err = getStreamSomehow(); const myConsole = new console.Console(out, err); myConsole.log('hello world'); // Prints: hello world, to out myConsole.log('hello %s', 'world'); // Prints: hello world, to out myConsole.error(new Error('Whoops, something bad happened')); // Prints: [Error: Whoops, something bad happened], to err const name = 'Will Robinson'; myConsole.warn(`Danger ${name}! Danger!`); // Prints: Danger Will Robinson! Danger!, to err ```
@see[source](https://github.com/nodejs/node/blob/v22.x/lib/console.js)
console
.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to `stdout` with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to [`printf(3)`](http://man7.org/linux/man-pages/man3/printf.3.html) (the arguments are all passed to [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args)). ```js const count = 5; console.log('count: %d', count); // Prints: count: 5, to stdout console.log('count:', count); // Prints: count: 5, to stdout ``` See [`util.format()`](https://nodejs.org/docs/latest-v22.x/api/util.html#utilformatformat-args) for more information.
@sincev0.1.100
log
(
const dizionario2: {
    [k: string]: {
        idCliente: string;
        prefisso: string;
        numero: string;
    };
}
dizionario2
);

Osserviamo attentamente e assicuriamoci di aver capito cosa sta succedendo:

  • Esegui questo nel TypeScript Playground, e verifica di vedere i log che ti aspetti.
  • Guarda da vicino i tipi degli elementi in dizionario1 e dizionario2 sopra, per convincerti che otteniamo un tipo di dizionario diverso da listaADizionario, a seconda del tipo dell'array che passiamo.

Questo è molto meglio del nostro "dizionario di any", perché non perdiamo alcuna informazione di tipo come effetto collaterale della trasformazione da lista a dizionario. È esattamente come il nostro archivista: qualunque cosa ci sia dentro gli scatoloni, sappiamo sempre cosa aspettarci quando li riapriamo.

Best practice

  • Usa ogni parametro di tipo almeno due volte. Se lo usi di meno, probabilmente stai facendo un cast con la keyword as. Guardiamo questo esempio:
ts
function function restituisciCome<T>(arg: any): TrestituisciCome<function (type parameter) T in restituisciCome<T>(arg: any): TT>(arg: anyarg: any): function (type parameter) T in restituisciCome<T>(arg: any): TT {
  return arg: anyarg; // 🚨 un `any` che *sembrerà* un `T`
}

// 🚨 PERICOLO! 🚨 (ma window non è affatto un numero!)
const 
const primo: number
primo
= function restituisciCome<number>(arg: any): numberrestituisciCome<number>(var window: Window & typeof globalThis
The **`window`** property of a Window object points to the window object itself. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/window)
window
);
const const stessaCosa: numberstessaCosa = var window: Window & typeof globalThis
The **`window`** property of a Window object points to the window object itself. [MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/window)
window
as any as number;

In questo esempio, abbiamo detto una bugia a TypeScript, affermando che window è un number (ma non lo è...). Ora, TypeScript non riuscirà a intercettare errori che dovrebbe intercettare, perché gli abbiamo tolto di mano l'unico strumento che aveva per verificare la nostra affermazione: usare T una sola volta, solo nel tipo di ritorno, significa che il compilatore non ha nessun altro punto del codice con cui "confrontare" quel T per validarlo.