Una configuración escrita como objeto puede encajar en un tipo amplio y aun así perder información útil para quien la consume. Lo contrario también es arriesgado: una aserción de tipo puede silenciar una clave incorrecta antes de que el código se ejecute.
El operador satisfies resuelve este caso para los valores escritos en el código. Comprueba que una expresión cumple un contrato y mantiene la forma específica inferida por esa expresión. Por eso resulta útil para configuraciones, mapas de rutas, feature flags y registros de tools.
Este artículo aplica la idea a un registro pequeño de tools. La fixture local se compiló con TypeScript 5.9.3: la versión corregida pasa, mientras que cambiar search por seach produce un error del compilador. No se afirma ningún benchmark ni experiencia de producción a partir del ejemplo.

Respuesta breve
- Usa satisfies cuando un valor literal debe cumplir un contrato sin perder sus claves y valores inferidos.
- Combina as const satisfies cuando el registro también debe conservar literales y ser de solo lectura.
- Usa una anotación cuando el tipo declarado y más amplio es la interfaz que debe ver el resto del programa.
- No uses satisfies para validar JSON, variables de entorno o argumentos recibidos en runtime.
¿Qué comprueba satisfies?
satisfies es una comprobación en tiempo de compilación. Dado un valor y un tipo a la derecha, TypeScript comprueba la compatibilidad y sigue usando el tipo inferido del valor en el resto del programa.
El operador se introdujo en TypeScript 4.9. La documentación oficial usa la misma idea para detectar una clave mal escrita en un objeto y, al mismo tiempo, mantener accesibles sus propiedades específicas. La fuente es la documentación de lanzamiento de TypeScript 4.9, consultada el 12 de octubre de 2026.
Considera este contrato de configuración:
type ToolDefinition = {
description: string;
run(input: { query: string }): Promise<unknown>;
};
type ToolName = "search" | "read";
const tools = {
search: {
description: "Search the indexed documents.",
run: async (input: { query: string }) => ({ query: input.query }),
},
read: {
description: "Read one indexed document.",
run: async (input: { query: string }) => ({ query: input.query }),
},
} as const satisfies Record<ToolName, ToolDefinition>;
type AvailableTool = keyof typeof tools;
const selected: AvailableTool = "search";
const selectedTool = tools[selected];
El contrato exige las dos claves de ToolName y comprueba la forma de cada definición. Al mismo tiempo, keyof typeof tools produce "search" | "read" a partir del valor escrito. El contrato del registro y el tipo específico del valor trabajan juntos, en vez de que uno reemplace al otro.
satisfies no es lo mismo que una anotación o as
Las tres formas parecen similares, pero comunican intenciones diferentes.
Anotación: el consumidor ve el tipo declarado
const tools: Record<ToolName, ToolDefinition> = {
search: {
description: "Search the indexed documents.",
run: async (input) => ({ query: input.query }),
},
read: {
description: "Read one indexed document.",
run: async (input) => ({ query: input.query }),
},
};
Esta opción es buena cuando el tipo amplio es exactamente la interfaz que quieres exponer. Los consumidores trabajan con Record<ToolName, ToolDefinition>. Los literales más específicos de la expresión dejan de ser el centro de la API.
Aserción: el código pide confianza
const tools = {
seach: {
description: "Search the indexed documents.",
run: async (input: { query: string }) => ({ query: input.query }),
},
} as Record<ToolName, ToolDefinition>;
as le dice al compilador que trate la expresión como otro tipo. No ejecuta una validación en runtime. El Handbook de tipos cotidianos, consultado el 12 de octubre de 2026, también explica que las aserciones desaparecen durante la compilación.
Aquí as es una mala opción porque puede ocultar la diferencia entre seach y search. Una aserción puede ser necesaria en una frontera que el compilador no puede demostrar, pero no debería ser el atajo predeterminado para comprobar un objeto literal.
satisfies: comprueba sin reemplazar el tipo del valor
const tools = {
seach: {
description: "Search the indexed documents.",
run: async (input: { query: string }) => ({ query: input.query }),
},
} as const satisfies Record<ToolName, ToolDefinition>;
Esto falla porque seach no está en ToolName y falta search. La fixture de este artículo produjo ese diagnóstico después del cambio deliberado de la clave.
Cómo usar as const satisfies en un registro
El patrón es más útil cuando un objeto tiene dos funciones:
- cumplir una forma mínima compartida;
- seguir siendo una fuente de tipos específicos para el programa.
Esto aparece en registros de comandos, rutas, eventos, feature flags y tools de agentes. Un registro de tools puede comprobar sus propias descripciones y firmas durante el build. Para la parte de selección de una tool por un agente, consulta cómo escribir descripciones de herramientas para agentes de IA. satisfies cubre el registro escrito en el código; no decide si el modelo seleccionó la tool correcta.
El paso siguiente tiene otra frontera. Después de seleccionar una tool, sus argumentos todavía deben comprobarse antes de ejecutarla. Es un problema de runtime, explicado en cómo validar tool calls en TypeScript. Mantener separados los contratos evita confundir una comprobación estática con la validación de una entrada externa.
Si el registro se indexa con una clave dinámica, la configuración del compilador también importa. noUncheckedIndexedAccess hace visible que una lectura como tools[name] puede no encontrar una entrada. satisfies ayuda a construir el registro, pero no demuestra que una clave recibida sea válida.
Cómo verificar el ejemplo localmente
Guarda el primer ejemplo como registry.ts y crea un tsconfig.json mínimo:
{
"compilerOptions": {
"strict": true,
"noEmit": true,
"target": "ES2022",
"types": []
},
"files": ["registry.ts"]
}
Después ejecuta:
npx -y -p typescript@5.9.3 tsc -p tsconfig.json --pretty false
El comando debe terminar sin diagnósticos cuando el registro contiene search y read. Para comprobar el contrato, cambia temporalmente search por seach. El compilador debería informar de la propiedad desconocida y de la clave esperada que falta. Corrige la clave y ejecuta el comando otra vez.
Esta prueba demuestra el comportamiento del compilador para un valor literal. No demuestra que sean válidos un JSON recibido por HTTP, una variable de entorno o los argumentos de una tool. En esa frontera, analiza o valida la entrada antes de tratarla como confiable. Cómo validar JSON externo antes de usarlo en TypeScript cubre ese problema diferente.
Cuándo no usar satisfies
No añadas satisfies a todos los objetos automáticamente. Estas señales indican que otra opción puede ser más clara:
- los consumidores solo deben ver una interfaz pública más amplia, así que una anotación comunica mejor la intención;
- el valor llega en runtime, por lo que los datos deben validarse antes de que el programa confíe en ellos;
- la diferencia entre las claves permitidas y las reales es una regla de negocio, así que un tipo Record estricto puede ser el contrato equivocado.
También evita combinar una aserción que deshaga la comprobación, como as unknown as Record<ToolName, ToolDefinition>. Si el contrato no se puede cumplir, el error debería llevarte a revisar los datos, el tipo o la frontera de validación.
Fuentes y límites
Las reglas sobre satisfies, las aserciones y la inferencia conservada se comprobaron en la documentación de lanzamiento de TypeScript 4.9 y el Handbook de tipos cotidianos. El soporte de @satisfies en JSDoc también aparece en las notas de TypeScript 5.0, pero no hace falta para el ejemplo de este artículo.
La fixture se compiló localmente con TypeScript 5.9.3 el 12 de octubre de 2026, usando strict, noEmit, target: ES2022 y types: []. La imagen es una ilustración explicativa generada para mostrar el flujo del contrato. La asistencia de IA apoyó la búsqueda, la redacción, la generación de la imagen, la traducción y la revisión de consistencia; no ejecutó el compilador ni sustituyó la verificación de fuentes y la responsabilidad editorial.