Referencia de tipos del SDK de TypeScript para bloques de contenido
El SDK @anthropic-ai/sdk tipifica el contenido de la respuesta de Claude como una unión discriminada de tipos de bloques de contenido, indexada por un campo type. Esta página es una referencia rápida para los tipos de bloque que verás con más frecuencia en response.content, y el patrón de reducción de tipo que TypeScript requiere antes de que puedas acceder a un campo específico del bloque.
Cómo usar esta referencia
- Busca el tipo de bloque por su cadena
.type, luego copia el fragmento de reducción de tipo que coincida con tu forma de iterar (cadena if vsswitch). - Trata
.typecomo el único campo en el que puedes confiar antes de la reducción. Cada otro campo es específico de un miembro de la unión. - Usa la tabla comparativa como una referencia cuando leas el bucle de otra persona sobre
response.contenty necesites saber qué expone un bloque determinado. - Recuerda que hay dos uniones relacionadas:
ContentBlock(lo que Claude te envía) y los tipos de parámetro de bloque comoToolResultBlockParam(lo que envías a Claude al construir mensajes). No son intercambiables.
Tipos de bloques de contenido de un vistazo
| Tipo | Discriminante .type | Campos clave | Dónde lo ves |
|---|---|---|---|
| TextBlock | "text" | .text: string | response.content, el texto normal de la respuesta del asistente |
| ToolUseBlock | "tool_use" | .id: string, .name: string, .input: unknown | response.content, cuando Claude decide llamar a una herramienta |
| ThinkingBlock | "thinking" | .thinking: string | response.content, solo cuando el pensamiento extendido está habilitado |
La unión que tipifica response.content incluye otros miembros además de estos tres para casos menos comunes (actividad de herramientas del lado del servidor, pensamiento redactado y similares). Los tres anteriores son aquellos a los que un bucle de manejo de respuesta típico reduce.
TextBlock
TextBlock es el texto de respuesta ordinario de Claude. Es el tipo de bloque al que reducirás con más frecuencia.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Di hola en una frase." }],
});
for (const block of response.content) {
if (block.type === "text") {
// TypeScript ahora sabe que `block` es un TextBlock aquí.
console.log(block.text);
}
}ToolUseBlock
ToolUseBlock aparece cuando Claude decide llamar a una de las herramientas que proporcionaste. .input está tipificado como unknown porque su forma depende del input_schema de la herramienta, por lo que aún necesitas validarlo o convertirlo antes de usarlo.
for (const block of response.content) {
if (block.type === "tool_use") {
// block.id, block.name, block.input están todos disponibles aquí.
console.log(block.id, block.name, block.input);
}
}ThinkingBlock
ThinkingBlock contiene la salida de pensamiento extendido de Claude. Solo aparece en response.content cuando el pensamiento extendido está habilitado para la solicitud; de lo contrario, simplemente está ausente, no presente con un valor vacío.
for (const block of response.content) {
if (block.type === "thinking") {
console.log(block.thinking);
}
}Reducción con una declaración switch
Una cadena if funciona, pero un switch en block.type se lee mejor una vez que estás manejando tres o más tipos de bloque en el mismo bucle, y mantiene el tipo reducido de cada rama aislado:
for (const block of response.content) {
switch (block.type) {
case "text":
console.log(block.text);
break;
case "tool_use":
console.log(block.name, block.input);
break;
case "thinking":
console.log(block.thinking);
break;
default:
// Otros tipos de bloque en la unión aterrizan aquí, sin reducir.
break;
}
}Filtrar a un solo tipo de bloque
Cuando solo te interesa un tipo de bloque, filtra primero en lugar de ramificar dentro del bucle. TypeScript reduce el tipo de elemento del array a través de un predicado de tipo:
const toolCalls = response.content.filter(
(block): block is Anthropic.ToolUseBlock => block.type === "tool_use"
);
for (const call of toolCalls) {
console.log(call.name, call.input); // no se necesita más reducción
}Los tipos de parámetros de bloque son una unión separada
TextBlock, ToolUseBlock y ThinkingBlock describen lo que Claude te envía. Cuando construyes mensajes para enviar a Claude, usas los tipos de parámetro correspondientes en su lugar, como ToolResultBlockParam para devolver el resultado de una herramienta. Estos tipos de parámetro no son los mismos tipos de TypeScript que los bloques de respuesta, incluso donde los nombres se superponen, así que no reutilices un ToolUseBlock que recibiste como si fuera contenido de entrada válido.
const toolResultMessage: Anthropic.MessageParam = {
role: "user",
content: [
{
type: "tool_result",
tool_use_id: call.id,
content: "72°F y soleado",
},
],
};Preguntas frecuentes
¿Por qué necesito verificar block.type antes de leer block.text?
Porque response.content está tipificado como una unión de tipos de bloque, y solo TextBlock tiene un campo .text. TypeScript no te permitirá acceder a .text en el tipo de unión directamente; la reducción con block.type === "text" le dice al compilador con qué miembro de la unión estás trabajando.
¿Qué sucede si intento acceder a .text sin reducir primero?
Un error de tipo en tiempo de compilación. TypeScript informa que .text no existe en los otros miembros de la unión ContentBlock, incluso si el valor fuera un TextBlock en tiempo de ejecución.
¿Es response.content siempre un array?
Sí. Incluso una respuesta que es una sola frase de texto se devuelve como un array con un TextBlock dentro. Siempre itera o indexa en él en lugar de tratar response.content como un solo bloque.
¿Cuál es la diferencia entre los tipos ContentBlock y ContentBlockParam?
Los tipos ContentBlock (TextBlock, ToolUseBlock, ThinkingBlock) describen los bloques que Claude te envía en una respuesta. Los tipos de parámetro (TextBlockParam, ToolResultBlockParam y similares) describen los bloques que envías a Claude al construir el array messages de una solicitud. Son uniones separadas, incluso cuando los nombres parecen similares.
¿Cuándo aparece realmente un ThinkingBlock en response.content?
Solo cuando el pensamiento extendido está habilitado para esa solicitud. Si el pensamiento no está habilitado, no aparece ningún ThinkingBlock, por lo que un bucle que nunca coincide con "thinking" en una solicitud sin pensamiento es un comportamiento esperado, no un error.
¿Puede una sola respuesta contener más de un ToolUseBlock?
Sí, a menos que el uso paralelo de herramientas esté deshabilitado para la solicitud. Una respuesta puede contener múltiples entradas ToolUseBlock junto con un TextBlock, por lo que un bucle debe manejar cada bloque de forma independiente en lugar de asumir como máximo una llamada a herramienta.
¿Por qué .input está tipificado como unknown en ToolUseBlock en lugar de algo más específico?
Porque la forma real de .input proviene del input_schema que definiste para esa herramienta, que el SDK no puede conocer de antemano con sus tipos estáticos. Valida o convierte .input contra tu propio esquema (por ejemplo, con Zod) antes de usar sus campos.
¿Debo usar una cadena if o una declaración switch para reducir block.type?
Ambas reducen correctamente. Una cadena if se lee bien para uno o dos tipos; un switch en block.type escala mejor una vez que estás ramificando en tres o más, y mantiene el tipo reducido de cada bloque case contenido dentro de esa rama.
¿Para qué se utiliza ToolResultBlockParam?
Es el bloque que agregas a un array messages para enviar el resultado de una herramienta de vuelta a Claude después de manejar un ToolUseBlock. Es un tipo de parámetro, no un tipo de respuesta, por lo que lo construyes tú mismo en lugar de recibirlo de la API.
¿Comparten TextBlock, ToolUseBlock y ThinkingBlock algún campo común además de type?
.type es el único campo garantizado en todos ellos, que es exactamente por qué es el discriminante. Cada otro campo (.text, .id/.name/.input, .thinking) pertenece a solo un miembro de la unión.
¿Los tipos de bloque no manejados romperán silenciosamente mi declaración switch?
No, pero caerán silenciosamente en tu caso default (o se omitirán si no tienes default), lo que puede ocultar nuevos tipos de bloque agregados a la unión con el tiempo. Agrega una rama default que al menos registre el block.type no reconocido para que los nuevos tipos de bloque no desaparezcan sin ser notados.
¿Cómo escribo una función que acepte cualquier bloque de contenido y lo reduzca internamente?
Tipifica el parámetro como el tipo de unión de bloque (por ejemplo, Anthropic.ContentBlock), luego reduce con las mismas comprobaciones block.type === "..." que se muestran arriba dentro del cuerpo de la función. El tipo de unión es lo que hace que la reducción esté disponible en primer lugar.
¿La reducción funciona con métodos de array como .filter(), no solo con bucles for-of?
Sí, siempre que la función de callback de filtro esté escrita como un predicado de tipo ((block): block is Anthropic.ToolUseBlock => ...). Una función de callback que devuelve un booleano simple filtra correctamente en tiempo de ejecución pero no reduce el tipo del array resultante para TypeScript.
Relacionado
- El modelo mental del SDK de TypeScript de Anthropic - cómo el cliente, las solicitudes y las respuestas encajan antes de llegar a los tipos de bloque individuales
- Conceptos básicos del SDK de TypeScript/JavaScript - instalar el SDK y hacer tu primera solicitud
- Definiciones de herramientas fuertemente tipadas con Zod en TypeScript - validar el
.inputde un ToolUseBlock contra un esquema real - Referencia de clases de error del SDK de TypeScript - la página de referencia correspondiente para clases de error tipadas en lugar de bloques de contenido
- Manejo de solicitudes de uso de herramientas y devolución de bloques de resultados de herramientas - el ciclo completo desde ToolUseBlock hasta una respuesta ToolResultBlockParam
Versiones de Stack: Escrito contra la línea de modelos de Claude actual a partir de ~junio de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado), y Claude Haiku 4.5 - y el SDK oficial de TypeScript
@anthropic-ai/sdk(última versión). Los nombres de los modelos, las versiones del SDK y los precios cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.