//
Busca en todas las páginas de la documentación
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Estrecha tipos de TypeScript en tiempo de ejecución usando guardas de tipo, funciones de aserción, el operador in y la palabra clave satisfies. Escribe código que le dé a TypeScript suficiente información para inferir tipos precisos en cada rama.
// Estrechamiento con typeof
function formatValue(value: string | number | boolean) {
if (typeof value === "string") {
return value.toUpperCase(); // TypeScript sabe: string
}
if (typeof value === "number") {
return value.toFixed(2); // TypeScript sabe: number
}
return value ? "Yes" : "No"; // TypeScript sabe: boolean
}
// Guarda de tipo personalizada con predicado "is"
type User = { kind: "user"; name: string; email: string };
type Admin = { kind: "admin"; name: string; permissions: string[] };
type Account = User | Admin;
function isAdmin(account: Account): account is Admin {
return account.kind === "admin";
}
function AccountBadge({ account }: { account: Account }) {
if (isAdmin(account)) {
return <span>Admin: {account.permissions.length} permissions</span>;
}
return <span>User: {account.email}</span>;
}// Estrechamiento con operador "in"
function renderAccount(account: Account) {
if ("permissions" in account) {
// TypeScript estrecha a Admin
return <div>{account.permissions.join(", ")}</div>;
}
// TypeScript estrecha a User
return <div>{account.email}</div>;
}// Palabra clave satisfies - validar sin ampliar
const ROUTES = {
home: "/",
about: "/about",
contact: "/contact",
} satisfies Record<string, string>;
// El tipo se preserva como { home: "/"; about: "/about"; contact: "/contact" }
// No se amplía a Record<string, string>
type RouteKey = keyof typeof ROUTES; // "home" | "about" | "contact"string, number, boolean, symbol, bigint, undefined, function y object.param is Type. Cuando la función devuelve true, TypeScript estrecha el parámetro a Type en el ámbito de llamada.in estrecha basándose en la existencia de propiedad. "email" in account estrecha a los miembros de la unión que tienen una propiedad email.instanceof estrecha instancias de clase: if (error instanceof TypeError) estrecha a TypeError.satisfies valida que una expresión se ajusta a un tipo sin cambiar su tipo inferido. Esto preserva tipos literales y formas específicas mientras asegura la corrección.asserts param is Type. Lanzan si la condición es falsa y estrechan el tipo para todo el código siguiente (no solo el bloque if).Función de aserción:
function assertIsString(value: unknown): asserts value is string {
if (typeof value !== "string") {
throw new Error(`Expected string, got ${typeof value}`);
}
}
function processInput(input: unknown) {
assertIsString(input);
// TypeScript sabe que input es string a partir de aquí
console.log(input.toUpperCase());
}Estrechamiento con Array.isArray:
function renderItems(data: string | string[]) {
if (Array.isArray(data)) {
return <ul>{data.map((item) => <li key={item}>{item}</li>)}</ul>;
}
return <p>{data}</p>;
}Estrechamiento de unión discriminada (switch):
type AsyncState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; error: Error };
function renderState<T>(state: AsyncState<T>, renderData: (data: T) => React.ReactNode) {
switch (state.status) {
case "idle":
return null;
case "loading":
return <Spinner />;
case "success":
return renderData(state.data); // Estrechado: data existe
case "error":
return <ErrorMessage error={state.error} />; // Estrechado: error existe
}
}satisfies con objetos de configuración:
type ColorConfig = Record<string, { bg: string; text: string }>;
const THEME = {
primary: { bg: "#3b82f6", text: "#ffffff" },
danger: { bg: "#ef4444", text: "#ffffff" },
success: { bg: "#22c55e", text: "#ffffff" },
} satisfies ColorConfig;
// THEME.primary está completamente tipado con valores literales
// THEME.nonExistent produciría un errorif y else. En el else de isAdmin(account), TypeScript sabe que account es User.satisfies se agregó en TypeScript 4.9. Es especialmente valioso para objetos de configuración, mapas de rutas y definiciones de constantes.if. Esto las hace poderosas para validación temprana al inicio de una función.if (x), if (x != null)) estrechan null y undefined pero también estrechan valores falsy como 0 y "". Usa != null para estrechamiento preciso de null/undefined.is. Si escribes una guarda defectuosa, TypeScript estará equivocado sobre el tipo estrechado.typeof null === "object" es una peculiaridad de JavaScript. Usa value !== null && typeof value === "object" para comprobaciones de objeto.const { status } = state; if (status === "success") { state.data } no estrecha state a la variante success. Usa state.status directamente.| Enfoque | Ventajas | Desventajas |
|---|---|---|
Guarda de tipo personalizada (is) | Reutilizable, legible, explícita | La corrección de la guarda es tu responsabilidad |
Operador in | No necesita función auxiliar | Solo comprueba la existencia de propiedad, no el tipo de valor |
instanceof | Integrado en JavaScript | Solo funciona con clases, no con interfaces |
satisfies | Valida sin ampliar | No crea un tipo reutilizable |
Función de aserción (asserts) | Estrecha todo el código siguiente | Debe lanzar, no puede devolver false |
Zod .parse() | Seguridad en tiempo de ejecución y compilación | Dependencia externa |
if, switch, typeof, in, etc.).typeof estrecha a: string, number, boolean, symbol, bigint, undefined, function y object.if (typeof value === "string"), TypeScript sabe que value es string.function isAdmin(account: Account): account is Admin {
return account.kind === "admin";
}param is Type.true, TypeScript estrecha el parámetro al tipo especificado.if donde se comprueba.if).false.satisfies valida que una expresión se ajusta a un tipo sin cambiar su tipo inferido.const x: T = ...) amplía el tipo a T.satisfies preserva tipos literales y formas específicas mientras asegura la corrección.typeof value === "object" solo no excluye null.value !== null && typeof value === "object" para comprobaciones de objeto seguras.if ("permissions" in account) {
// TypeScript estrecha al miembro de la unión que tiene "permissions"
account.permissions; // OK
}const { status } = state; if (status === "success") { state.data } falla porque TypeScript pierde la conexión entre status y state.state.status directamente en la comprobación para mantener el estrechamiento.// Con satisfies: preserva tipos literales
const ROUTES = {
home: "/",
about: "/about",
} satisfies Record<string, string>;
// Tipo: { home: "/"; about: "/about" }
// Con anotación: amplía a Record<string, string>
const ROUTES2: Record<string, string> = { home: "/", about: "/about" };satisfies cuando quieras validación Y tipos literales preservados.else de if (isAdmin(account)), TypeScript sabe que account es User (el otro miembro de la unión).typeof, in, instanceof y guardas personalizadas.function renderItems(data: string | string[]) {
if (Array.isArray(data)) {
return data.map((item) => item); // data es string[]
}
return data; // data es string
}Revisado por Chris St. John·Última actualización: 19 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥