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
Narrowing dei tipi in TypeScriptExplained
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.