Tag: typescript, javascript, types, generics, utility-types, frontend, backend
Livello: intermedio
TL;DR: Superset tipizzato di JavaScript con compilazione via type erasure, type inference, strict checking e modellazione avanzata con union, generics e narrowing.
Superset sintattico di JavaScript compilato via type erasure: nessun overhead a runtime.
Sistema di tipi strutturale (duck typing): compatibilità basata sulla forma dei dati, non sul nome nominale.
Modalità strict abilitata in tsconfig.json: include noImplicitAny, strictNullChecks e controlli rigorosi.
Tipi primitivi estesi con unknown, never, any, void e tipi unione/intersezione.
unknown è un top type type-safe: richiede narrowing o type assertion prima dell'uso.
never è il bottom type: rappresenta valori che non possono mai verificarsi o computazioni che non terminano.
Type narrowing: raffinamento del tipo tramite typeof, instanceof, in, o custom type guards.
Interfacce estendibili tramite extends e declaration merging; Type alias usati per unioni, tuple e mapped types.
Utility types built-in: Partial, Required, Readonly, Pick, Omit, Record, Extract, Exclude.
Generics permettono di parametrizzare funzioni, classi e tipi mantenendo la correlazione tra tipi di input e output.
Q: Qual è la differenza sostanziale tra type e interface?R: Uso interface per definire la forma di oggetti o classi estendibili tramite ereditarietà o declaration merging. Uso type quando mi servono tipi unione, primitive, tuple o mapped types avanzati.
Q: Perché preferire unknown rispetto ad any?R: any disabilita completamente il type checker annullando la sicurezza. unknown impone di validare o restringere il tipo a runtime prima di accedere a proprietà o metodi.
Q: Come gestisci il type narrowing con tipi discriminati (discriminated unions)?R: Definisco un campo comune costante letterale, tipicamente type o kind, e uso uno switch o if su quel campo per consentire a TypeScript di restringere automaticamente il tipo nel blocco.
Q: Cosa si intende per type erasure?R: Tutti i tipi, interfacce e annotazioni TypeScript vengono rimossi durante la compilazione. Il codice JavaScript risultante a runtime non ha consapevolezza dei tipi TypeScript.
Q: Come rendi esaustivo un controllo di rami (exhaustive check)?R: Assegno il valore residuo a una variabile di tipo never nel blocco default. Se aggiungo un nuovo tipo all'unione senza gestirlo, la compilazione fallisce.
Uso improprio delle asserzioni di tipo as Type per silenziare errori del compilatore anziché correggere o verificare il tipo.
Assunzione errata che i tipi TypeScript validino i dati a runtime (es. payload API senza librerie di validazione come Zod).
Dimenticanza di abilitare strictNullChecks, consentendo l'assegnazione silenziosa di null o undefined a qualsiasi tipo.
Confusione tra any (disabilita controlli) e unknown (forza il narrowing esplicito).
Sovrascrittura accidentale causata da declaration merging involontario usando interfacce duplicate con lo stesso nome.
# Inizializzare un progetto TypeScript con tsconfig.json
npx tsc --init
# Compilare il progetto in modalità watch
npx tsc --watch
TypeScript
// Discriminated union e exhaustive checking
type SuccessState = { status: 'success'; data: string[] };
type ErrorState = { status: 'error'; error: Error };
type LoadingState = { status: 'loading' };
type State = SuccessState | ErrorState | LoadingState;
function handleState(state: State): string {
switch (state.status) {
case 'success':
return `Loaded ${state.data.length} items`;
case 'error':
return state.error.message;
case 'loading':
return 'Loading...';
default: {
const _exhaustiveCheck: never = state;
return _exhaustiveCheck;
}
}
}
TypeScript
// Custom Type Guard con predicato di tipo
interface User {
id: string;
name: string;
}
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value &&
typeof (value as Record<string, unknown>).id === 'string' &&
typeof (value as Record<string, unknown>).name === 'string'
);
}
TypeScript
// Utility types e Generics con vincoli (constraints)
type ApiResponse<T> = {
data: T;
timestamp: number;
};
interface Entity {
id: string;
}
function updateEntity<T extends Entity>(original: T, updates: Partial<Omit<T, 'id'>>): T {
return { ...original, ...updates };
}
[x] Regole base di type inference e annotazioni primitive
[x] Differenza pratica tra type e interface
[ ] Mapped types e conditional types (infer, Exclude, Extract)
[ ] Validazione a runtime di contratti API con Zod o TypeBox
[ ] Configurazione ottimale dei flag di strictness in tsconfig.json