Referência de Tipos do SDK TypeScript para Blocos de Conteúdo
O SDK @anthropic-ai/sdk tipa o conteúdo de uma resposta do Claude como uma união discriminada de tipos de bloco de conteúdo, indexada por um campo type. Esta página é uma referência rápida para os tipos de bloco que você verá com mais frequência em response.content e o padrão de "narrowing" (estreitamento de tipo) que o TypeScript exige antes que você possa acessar um campo específico do bloco.
Como Usar Esta Referência
- Procure o tipo de bloco pelo seu string
.type, depois copie o snippet de "narrowing" que corresponde à forma como você está iterando (cadeiaifvsswitch). - Trate
.typecomo o único campo em que você pode confiar antes do "narrowing". Todos os outros campos são específicos de um membro da união. - Use a tabela de comparação como um guia quando estiver lendo o loop de outra pessoa sobre
response.contente precisar saber o que um determinado bloco expõe. - Lembre-se de que existem duas uniões relacionadas:
ContentBlock(o que o Claude envia de volta para você) e os tipos de parâmetro de bloco, comoToolResultBlockParam(o que você envia para o Claude ao construir mensagens). Eles não são intercambiáveis.
Tipos de Bloco de Conteúdo em Resumo
| Tipo | Discriminante .type | Campos Principais | Onde você vê |
|---|---|---|---|
| TextBlock | "text" | .text: string | response.content, o texto normal da resposta do assistente |
| ToolUseBlock | "tool_use" | .id: string, .name: string, .input: unknown | response.content, quando o Claude decide chamar uma ferramenta |
| ThinkingBlock | "thinking" | .thinking: string | response.content, apenas quando o pensamento estendido está habilitado |
A união que tipa response.content inclui outros membros além desses três para casos menos comuns (atividade de ferramenta no lado do servidor, pensamento redigido e similares). Os três acima são aqueles nos quais um loop típico de tratamento de resposta faz o "narrowing".
TextBlock
TextBlock é o texto comum da resposta do Claude. É o tipo de bloco para o qual você fará "narrowing" com mais frequência.
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: "Diga olá em uma frase." }],
});
for (const block of response.content) {
if (block.type === "text") {
// O TypeScript agora sabe que `block` é um TextBlock aqui.
console.log(block.text);
}
}ToolUseBlock
ToolUseBlock aparece quando o Claude decide chamar uma das ferramentas que você forneceu. .input é tipado como unknown porque sua forma depende do próprio input_schema da ferramenta, então você ainda precisa validá-lo ou fazer um "cast" antes de usá-lo.
for (const block of response.content) {
if (block.type === "tool_use") {
// block.id, block.name, block.input estão todos disponíveis aqui.
console.log(block.id, block.name, block.input);
}
}ThinkingBlock
ThinkingBlock carrega a saída de pensamento estendido do Claude. Ele só aparece em response.content quando o pensamento estendido está ativado para a solicitação; caso contrário, ele simplesmente está ausente, não presente com um valor vazio.
for (const block of response.content) {
if (block.type === "thinking") {
console.log(block.thinking);
}
}Narrowing com uma Instrução switch
Uma cadeia if funciona, mas um switch em block.type é mais legível quando você está lidando com três ou mais tipos de bloco no mesmo loop, e mantém o tipo estreitado de cada ramificação isolado:
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:
// Outros tipos de bloco na união caem aqui, não estreitados.
break;
}
}Filtrando para um Único Tipo de Bloco
Quando você se importa apenas com um tipo de bloco, filtre primeiro em vez de ramificar dentro do loop. O TypeScript estreita o tipo do elemento do array através de um 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); // nenhum narrowing adicional necessário
}Tipos de Parâmetro de Bloco São uma União Separada
TextBlock, ToolUseBlock e ThinkingBlock descrevem o que o Claude envia de volta para você. Ao construir mensagens para enviar ao Claude, você usa os tipos de parâmetro correspondentes em vez disso, como ToolResultBlockParam para retornar o resultado de uma ferramenta. Esses tipos de parâmetro não são os mesmos tipos TypeScript dos blocos de resposta, mesmo onde os nomes se sobrepõem, portanto, não reutilize um ToolUseBlock que você recebeu como se fosse conteúdo de entrada válido.
const toolResultMessage: Anthropic.MessageParam = {
role: "user",
content: [
{
type: "tool_result",
tool_use_id: call.id,
content: "72°F e ensolarado",
},
],
};FAQs
Por que preciso verificar block.type antes de ler block.text?
Porque response.content é tipado como uma união de tipos de bloco, e apenas TextBlock tem um campo .text. O TypeScript não permitirá que você acesse .text diretamente no tipo de união; fazer "narrowing" com block.type === "text" informa ao compilador com qual membro da união você está trabalhando.
O que acontece se eu tentar acessar .text sem fazer narrowing primeiro?
Um erro de tipo em tempo de compilação. O TypeScript relata que .text não existe nos outros membros da união ContentBlock, mesmo que o valor seja um TextBlock em tempo de execução.
response.content é sempre um array?
Sim. Mesmo uma resposta que é uma única frase de texto retorna como um array com um TextBlock nele. Sempre itere ou acesse por índice em vez de tratar response.content como um único bloco.
Qual é a diferença entre os tipos ContentBlock e ContentBlockParam?
Os tipos ContentBlock (TextBlock, ToolUseBlock, ThinkingBlock) descrevem os blocos que o Claude envia para você em uma resposta. Os tipos de parâmetro (TextBlockParam, ToolResultBlockParam e similares) descrevem os blocos que você envia ao Claude ao construir o array messages de uma solicitação. São uniões separadas, mesmo quando os nomes parecem semelhantes.
Quando um ThinkingBlock realmente aparece em response.content?
Apenas quando o pensamento estendido está habilitado para essa solicitação. Se o pensamento não estiver habilitado, nenhum ThinkingBlock aparecerá, então um loop que nunca corresponde a "thinking" em uma solicitação sem pensamento é o comportamento esperado, não um bug.
Uma única resposta pode conter mais de um ToolUseBlock?
Sim, a menos que o uso paralelo de ferramentas esteja desabilitado para a solicitação. Uma resposta pode conter várias entradas ToolUseBlock ao lado de um TextBlock, então um loop deve lidar com cada bloco independentemente em vez de assumir no máximo uma chamada de ferramenta.
Por que .input é tipado como unknown em ToolUseBlock em vez de algo mais específico?
Porque a forma real de .input vem do input_schema que você definiu para essa ferramenta, que o SDK não tem como saber antecipadamente com seus tipos estáticos. Valide ou faça um "cast" de .input contra seu próprio schema (por exemplo, com Zod) antes de usar seus campos.
Devo usar uma cadeia if ou uma instrução switch para fazer narrowing em block.type?
Ambos fazem "narrowing" corretamente. Uma cadeia if é legível para um ou dois tipos; um switch em block.type escala melhor quando você está ramificando em três ou mais, e mantém o tipo estreitado de cada bloco case contido nesse ramo.
Para que serve ToolResultBlockParam?
É o bloco que você adiciona a um array messages para enviar o resultado de uma ferramenta de volta ao Claude após o tratamento de um ToolUseBlock. É um tipo de parâmetro, não um tipo de resposta, então você o constrói em vez de recebê-lo da API.
TextBlock, ToolUseBlock e ThinkingBlock compartilham algum campo comum além de type?
.type é o único campo garantido em todos eles, que é exatamente por que é o discriminante. Todos os outros campos (.text, .id/.name/.input, .thinking) pertencem a apenas um membro da união.
Tipos de bloco não tratados quebrarão silenciosamente minha instrução switch?
Não, mas eles cairão silenciosamente para o seu caso default (ou serão ignorados se você não tiver um default), o que pode ocultar novos tipos de bloco adicionados à união ao longo do tempo. Adicione um ramo default que pelo menos registre o block.type não reconhecido para que novos tipos de bloco não desapareçam sem serem notados.
Como escrevo uma função que aceita qualquer bloco de conteúdo e faz narrowing internamente?
Tipifique o parâmetro como o tipo de união de bloco (por exemplo, Anthropic.ContentBlock), depois faça "narrowing" com as mesmas verificações block.type === "..." mostradas acima dentro do corpo da função. O tipo de união é o que torna o "narrowing" disponível em primeiro lugar.
O narrowing funciona com métodos de array como .filter(), não apenas loops for-of?
Sim, desde que o callback do filtro seja escrito como um predicado de tipo ((block): block is Anthropic.ToolUseBlock => ...). Um callback que retorna um booleano simples filtra corretamente em tempo de execução, mas não faz "narrowing" do tipo do array resultante para o TypeScript.
Relacionados
- O Modelo Mental do SDK TypeScript da Anthropic - como o cliente, as solicitações e as respostas se encaixam antes de você chegar aos tipos de bloco individuais
- Noções Básicas do SDK TypeScript/JavaScript - instalando o SDK e fazendo sua primeira solicitação
- Definições de Ferramentas Fortemente Tipadas com Zod em TypeScript - validando o
.inputde um ToolUseBlock contra um schema real - Referência de Classe de Erro do SDK TypeScript - a página de referência correspondente para classes de erro tipadas em vez de blocos de conteúdo
- Tratando Solicitações de Uso de Ferramentas e Retornando Blocos de Resultado de Ferramentas - o ciclo completo de ToolUseBlock para um response ToolResultBlockParam
Versões de Stack: Escrito contra a linha de modelos Claude atual em ~junho de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (o padrão) e Claude Haiku 4.5 - e o SDK oficial
@anthropic-ai/sdkTypeScript (última versão). Nomes de modelos, versões de SDK e preços mudam rapidamente - verifique os detalhes atuais em platform.claude.com/docs antes de confiar neles.