Skip to content

Narrowing dei tipi in TypeScript spiegati

I modi in cui TypeScript restringe un tipo dentro un ramo, raggruppati per tecnica: guard integrati, predicati personalizzati, funzioni di asserzione, unioni discriminate, flusso di uguaglianza e truthiness, narrowing con alias e differito. Ogni riga abbina la tecnica a un esempio di una riga.

Il narrowing è il modo in cui TypeScript trasforma un tipo ampio in uno più ristretto dentro un ramo di codice, così può dimostrare che un accesso a una proprietà è sicuro. Ogni controllo (typeof, in, un predicato, un discriminante) dice al compilatore: da qui in poi, il valore è più specifico. Le tecniche qui sotto sono il set di lavoro.

Tabella di riferimento · 23 voci
23 of 23 rows
Guard integrati
Restringe i primitivi: string, number, boolean e altri.if (typeof x === 'string') x.toUpperCase()
Restringe a un'istanza di una classe o di un tipo costruibile.if (e instanceof Error) e.message
Restringe verificando che una proprietà esista sul valore.if ('id' in obj) obj.id
Restringe qualsiasi valore a un array; restringe un'unione al suo membro array.if (Array.isArray(x)) x.map(f)
Guard personalizzati
Una funzione predicato il cui valore di ritorno restringe l'argomento.function isUser(x): x is User { return !!x.id }
Un predicato può restringere a un'unione di tipi, non solo a uno singolo.function isKey(x): x is string | number
Un predicato a intersezione mantiene il tipo in input e vi aggiunge campi.function hasId(x): x is x & { id: string }
Una funzione di asserzione che lancia un'eccezione se x non è del tipo.function assertUser(x): asserts x is User
Unioni discriminate
Restringe un'unione tramite un campo letterale condiviso, con switch o if.type E = { kind: 'a'; a: number } | { kind: 'b'; b: string }
Ogni case restringe a un membro dell'unione.switch (u.kind) { case 'a': u.a }
Restringe un'unione senza tag quando una proprietà esiste solo su un membro.if ('b' in u) u.b
Ogni case è una condizione; il case corrisposto restringe il valore.switch (true) { case typeof x === 'string': }
Il case default assegna a never, dimostrando che lo switch è esaustivo.default: { const x: never = u }
Uguaglianza e flusso
Rimuove null e undefined dopo un controllo di uguaglianza.if (x === null) return; x.toFixed()
Rimuove i valori falsy (0, '', null, undefined, NaN).if (!x) return; // x is defined here
Una proprietà concatenata truthy dimostra che il valore di base è presente.if (user?.active) user.name
L'asserzione non-null rimuove null e undefined senza alcun controllo.x!.toFixed(2)
Assegnazione definita: dichiara che x riceve un valore prima di essere letto.let name!: string; init()
Il narrowing vale dentro il ramo e dopo i return anticipati.if (!arr) return; arr.map(...)
Alias e narrowing differito
Un const boolean che contiene un controllo restringe ovunque venga testato.const isStr = typeof x === 'string'; if (isStr) …
Una variabile const mantiene il proprio narrowing dentro le closure che la catturano.const s = get(); if (s) use(() => s.length)
Da TS 5.4, un let o un parametro mantiene il narrowing nelle closure dopo la sua ultima assegnazione.let n: string | null = get(); if (n) use(() => n.length)
unknown non è utilizzabile finché una guard non lo restringe a un tipo reale.if (typeof u === 'string') u.length