Skip to content

Estrechamiento de tipos en TypeScript explicado

Las formas en que TypeScript estrecha un tipo dentro de una rama, agrupadas por técnica: guardias integradas, predicados propios, funciones de aserción, uniones discriminadas, flujo de igualdad y veracidad, y estrechamiento por alias y diferido. Cada fila empareja la técnica con un ejemplo de una línea.

El estrechamiento es cómo TypeScript convierte un tipo amplio en uno más estrecho dentro de una rama de código, para poder demostrar que un acceso a una propiedad es seguro. Cada comprobación (typeof, in, un predicado, un discriminador) le dice al compilador: a partir de aquí, el valor es más específico. Las técnicas siguientes son el conjunto de trabajo.

Tabla de referencia · 23 entradas
23 of 23 rows
Guardias integradas
Estrecha primitivos: string, number, boolean y más.if (typeof x === 'string') x.toUpperCase()
Estrecha a una instancia de una clase o de un tipo construible.if (e instanceof Error) e.message
Estrecha comprobando que una propiedad existe en el valor.if ('id' in obj) obj.id
Estrecha cualquier valor a un array; estrecha una unión a su miembro array.if (Array.isArray(x)) x.map(f)
Guardias personalizadas
Una función predicado cuyo retorno estrecha el argumento.function isUser(x): x is User { return !!x.id }
Un predicado puede estrechar a una unión de tipos, no solo a uno.function isKey(x): x is string | number
Un predicado de intersección conserva el tipo de entrada y le añade campos.function hasId(x): x is x & { id: string }
Una función de aserción que lanza si x no es el tipo.function assertUser(x): asserts x is User
Uniones discriminadas
Estrecha una unión por un campo literal compartido mediante switch o if.type E = { kind: 'a'; a: number } | { kind: 'b'; b: string }
Cada case estrecha a un miembro de la unión.switch (u.kind) { case 'a': u.a }
Estrecha una unión sin etiqueta cuando una propiedad existe solo en un miembro.if ('b' in u) u.b
Cada case es una condición; el case que coincide estrecha el valor.switch (true) { case typeof x === 'string': }
El caso por defecto asigna a never, demostrando que el switch es exhaustivo.default: { const x: never = u }
Igualdad y flujo
Elimina null y undefined tras una comprobación de igualdad.if (x === null) return; x.toFixed()
Elimina los valores falsy (0, '', null, undefined, NaN).if (!x) return; // x is defined here
Una propiedad encadenada truthy demuestra que el valor base está presente.if (user?.active) user.name
La aserción de no nulo elimina null y undefined sin comprobación.x!.toFixed(2)
Asignación definida: declara que x se asigna antes de leerse.let name!: string; init()
El estrechamiento aplica dentro de la rama y tras los retornos anticipados.if (!arr) return; arr.map(...)
Alias y estrechamiento diferido
Un booleano const que guarda una comprobación estrecha dondequiera que se evalúe.const isStr = typeof x === 'string'; if (isStr) …
Una variable const conserva su estrechamiento dentro de los closures que la capturan.const s = get(); if (s) use(() => s.length)
Desde TS 5.4, un let o parámetro conserva el estrechamiento en closures tras su última asignación.let n: string | null = get(); if (n) use(() => n.length)
unknown no puede usarse hasta que una guardia lo estrecha a un tipo real.if (typeof u === 'string') u.length