Processamento JSON em TypeScript: do parsing básico à tipagem estrita
TypeScript, sendo uma extensão do JavaScript, herda todos os métodos nativos de trabalho com JSON, mas adiciona a eles um poderoso sistema de tipos. No entanto, o JSON.parse() padrão retorna o tipo any, o que anula todas as vantagens da tipagem estática. Neste artigo, veremos como processar JSON de forma segura e eficiente em TypeScript, usando tanto recursos nativos quanto bibliotecas especializadas.
O problema do JSON.parse padrão
Considere um cenário típico:
const jsonString = '{"name":"Alice","age":30}';const user: any = JSON.parse(jsonString); // tipo anyconsole.log(user.name.toUpperCase()); // Erro em tempo de execução se name estiver ausenteTypeScript não avisará se a estrutura do JSON não corresponder ao esperado. A solução é usar asserção de tipo (type assertion) ou, melhor ainda, validação em tempo de execução.
Asserção de tipo básica (Type Assertion)
A maneira mais simples é especificar explicitamente o tipo do resultado:
interface User { id: number; name: string; email?: string;}
const raw = '{"id":1,"name":"Bob"}';const user = JSON.parse(raw) as User;console.log(user.name); // TypeScript sabe que é stringDesvantagem: se o JSON vier com outros campos, o erro ocorrerá apenas em tempo de execução. Isso não é seguro ao trabalhar com APIs externas.
Tipos recursivos e condicionais para JSON
TypeScript permite descrever qualquer JSON por meio de um tipo recursivo:
type JSONValue = | string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
function safeParse(json: string): JSONValue | Error { try { return JSON.parse(json) as JSONValue; } catch (e) { return new Error('Invalid JSON'); }}Essa abordagem garante que o resultado será sempre uma estrutura JSON válida, mas não verifica a forma específica.
Biblioteca Zod — validação de esquemas em tempo de execução
Zod é a biblioteca mais popular para validação declarativa de dados em TypeScript. Ela permite descrever um esquema e obter o tipo automaticamente a partir dele.
Instalação
npm install zodExemplo de uso
import { z } from 'zod';
// Descrevendo o esquemaconst UserSchema = z.object({ id: z.number().positive(), name: z.string().min(1), email: z.string().email().optional(), role: z.enum(['admin', 'user']).default('user'),});
// Inferindo o tipo a partir do esquematype User = z.infer<typeof UserSchema>;
// Parsing seguroconst result = UserSchema.safeParse(JSON.parse(rawJson));
if (result.success) { // result.data tem o tipo User console.log(result.data.name);} else { console.error(result.error.format());}Zod verifica automaticamente tipos, obrigatoriedade de campos, valores padrão e retorna erros detalhados. É a escolha ideal para processar dados de APIs REST ou arquivos de configuração.
Biblioteca io-ts — abordagem funcional
io-ts é baseada em programação funcional e na biblioteca fp-ts. Ela usa composição de codecs para decodificar/codificar dados.
Exemplo
import * as t from 'io-ts';import { isRight } from 'fp-ts/lib/Either';
const UserCodec = t.type({ id: t.number, name: t.string, tags: t.array(t.string),});
const decoded = UserCodec.decode(JSON.parse(raw));
if (isRight(decoded)) { // decoded.right — objeto tipado console.log(decoded.right.name);} else { // decoded.left — erros de validação console.log(decoded.left);}io-ts é mais rigoroso e matematicamente correto, mas requer compreensão de conceitos funcionais (Either, pipe).