Menu

as in TypeScript: type assertion e casting spiegati

La parola chiave as dice a TypeScript di trattare un valore come se avesse un altro tipo. Non è un cast: a runtime non viene convertito né controllato nulla. Scopri la sintassi con as e con le parentesi angolari, cosa permette il compilatore, le doppie asserzioni tramite unknown e quando un type guard è lo strumento migliore.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

value as Type è una type assertion: dice a TypeScript di trattare value come Type. Molti la chiamano cast, ma è solo un'istruzione per il compilatore. Viene eliminata dall'output JavaScript, non converte nulla e a runtime non controlla nulla.

Questo è l'uso tipico: sai di un valore più di quanto possa sapere il compilatore (qui, la forma di un JSON) e lo dichiari. Se sbagli, niente ti avvisa. Le sezioni seguenti mostrano cosa significa e quando un controllo a runtime è la scelta migliore.

as e la sintassi con le parentesi angolari

La stessa asserzione si può scrivere in due modi:

const someValue: unknown = "hello";
const a = someValue as string;   // as syntax
const b = <string>someValue;     // angle-bracket syntax, same meaning

La forma con le parentesi angolari non è ammessa nei file .tsx, dove <string> verrebbe letto come un tag JSX. Usa as ovunque e il problema non si pone. Le asserzioni hanno una precedenza bassa, quindi racchiudile tra parentesi quando prosegui l'espressione: (value as string).length.

Le asserzioni non convertono i valori

Questa è la parte che causa bug veri. Un'asserzione cambia ciò che il compilatore crede di un valore, non il valore stesso:

Il compilatore crede che asserted sia un number, quindi asserted + 1 supera il controllo come operazione aritmetica. A runtime è ancora la stringa "42" e JavaScript concatena. Per cambiare il tipo di un valore, convertilo: Number(x), String(x), Boolean(x), BigInt(x), new Date(x). La pagina da stringa a numero confronta le funzioni di conversione.

VuoiScriviEffetto a runtime
Comunicare al compilatore un tipo che conoscix as Tnessuno
Trasformare una stringa in un numeroNumber(x), parseInt(x, 10)converte
Trasformare qualsiasi cosa in una stringaString(x), `${x}`converte
Controllare prima il tipoun type guard, typeof, instanceofcontrolla

Cosa permette il compilatore

as non è illimitato. TypeScript permette x as T quando uno dei due tipi è assegnabile all'altro: allargare ("a" as string, dog as Animal) e restringere (animal as Dog, unknown as User) vanno bene entrambi. Quando i tipi non si sovrappongono affatto, lo rifiuta:

Il compilatore segnala index.ts(3,11): error TS2352: Conversion of type 'string' to type 'number' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Il messaggio stesso indica la scappatoia: input as unknown as number. Quella doppia asserzione compila, ed è sbagliata a runtime esattamente come l'esempio qui sopra. Quando senti il bisogno di usarla, di solito la soluzione giusta è una conversione (Number(input)) o un tipo diverso.

La regola della sovrapposizione è permissiva con gli oggetti. Un oggetto letterale che ha alcune delle proprietà viene accettato, ed è così che as fa passare in silenzio oggetti incompleti:

Un'annotazione (const draft: User = { name: "Ada" }) o satisfies User segnalerebbe l'email mancante (TS2741). Usa as su un oggetto letterale solo quando intendi davvero completarlo più avanti, e preferisci costruire l'oggetto completo.

as const è diverso

as const sembra un'asserzione ma fa il contrario di allentare i controlli: rende un letterale il più stretto possibile. Le stringhe restano tipi letterali, gli array diventano tuple readonly e le proprietà degli oggetti diventano readonly.

È sicuro, perché descrive esattamente il letterale invece di affermare qualcosa che il compilatore non può vedere. (Il sizes as readonly string[] dentro isSize è un'asserzione che allarga il tipo, anch'essa sicura: permette a includes di accettare qualsiasi stringa.) Approfondisci nei literal types.

Quando un type guard è lo strumento migliore

as è un'affermazione; un type guard è un controllo. Al confine in cui i dati arrivano da fuori dal tuo codice (JSON, fetch, localStorage, input dell'utente, un messaggio), l'affermazione può essere falsa, e un'asserzione trasforma un errore chiaro al confine in uno confuso da qualche altra parte.

Una guida di massima agli strumenti che si somigliano:

StrumentoControlla in compilazioneControlla a runtimeUsalo quando
Annotazione const x: T = ...sì, completamentenocostruisci tu il valore
satisfies Tsì, completamente, mantiene il tipo dedottonooggetti letterali, configurazione
as Tsolo "i tipi si sovrappongono?"none sai più del compilatore
x!rimuove solo null / undefinednosai che un valore è impostato
Type guard x is Til corpo del guard è codice normalesìdati che arrivano da fuori

Restano due buoni usi di as: restringere qualcosa che il compilatore non riesce a seguire (una voce di una Map impostata due righe prima, un valore da una libreria senza tipi) e il codice di test che costruisce fixture parziali. Tienili piccoli e vicini al punto in cui sai che l'affermazione è vera.

Domande frequenti

Cosa fa as in TypeScript?

value as Type è una type assertion: dice al compilatore di trattare value come Type da quel punto in poi. Viene rimossa dal JavaScript compilato, quindi non esegue alcuna conversione né alcun controllo a runtime. Se l'asserzione è sbagliata, il programma fallisce più avanti, nel punto in cui si usa il tipo sbagliato.

Come faccio un cast di tipo in TypeScript?

TypeScript non ha cast a runtime. Usa as (o la vecchia forma <Type>value) per cambiare il tipo statico quando ne sai più del compilatore. Per convertire davvero un valore, chiama una funzione: Number("42"), String(42), Boolean(x), new Date(text).

Cosa significa "as unknown as" in TypeScript?

È una doppia asserzione. TypeScript rifiuta x as T quando i due tipi non si sovrappongono affatto (errore TS2352), e passare prima per unknown aggira quel controllo, perché qualsiasi cosa si può asserire verso e da unknown. Disattiva del tutto il controllo dei tipi per quel valore, quindi riservala ai test e al codice in cui hai verificato il tipo in un altro modo.

Che differenza c'è tra as e le parentesi angolari in TypeScript?

Nessuna nel significato: <string>value e value as string sono la stessa asserzione. La forma con le parentesi angolari non si può usare nei file .tsx perché va in conflitto con JSX, quindi as è la forma che usano tutti.

Che differenza c'è tra as e satisfies?

as sostituisce il tipo dedotto e controlla molto poco (le proprietà mancanti sono ammesse). satisfies controlla il valore rispetto a un tipo, segnalando le proprietà mancanti o in più, e mantiene il tipo preciso dedotto. Preferisci satisfies per gli oggetti letterali e usa as solo quando ne sai davvero più del compilatore.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA