Introdução: por que a documentação é um investimento, e não uma perda de tempo
Todo desenvolvedor já passou pela situação: ao retornar ao próprio código depois de um mês, você tem dificuldade em lembrar para que serve determinado parâmetro. O que dizer então de novos membros da equipe que tentam entender seu projeto. A documentação de qualidade para um projeto TypeScript não é apenas um complemento agradável, mas um elemento criticamente importante que acelera a integração, reduz o número de bugs e torna o código sustentável.
TypeScript, sendo uma extensão do JavaScript, fornece um poderoso sistema de tipos. No entanto, os tipos por si só nem sempre respondem à pergunta "por quê?". A documentação preenche essa lacuna. Neste artigo, abordaremos o ciclo completo: desde a escolha do estilo de comentários até a geração de um site estático com documentação.
1. Fundamentos: JSDoc, TSDoc e TypeScript
Para documentar código TypeScript, historicamente existem dois padrões principais: JSDoc e TSDoc. JSDoc é o bom e velho formato que veio do mundo JavaScript. TSDoc é um padrão mais moderno, otimizado especificamente para TypeScript. Ambas as abordagens usam comentários no formato /** ... */.
Vejamos um exemplo básico usando JSDoc:
/** * Calcula a soma de dois números. * @param a - Primeira parcela * @param b - Segunda parcela * @returns Soma de a e b */function add(a: number, b: number): number { return a + b;}E aqui está como fica no estilo TSDoc usando as tags @param e @returns:
/** * Calcula a soma de dois números. * @param a - Primeira parcela * @param b - Segunda parcela * @returns Soma de a e b */function add(a: number, b: number): number { return a + b;}A diferença é mínima, mas o TSDoc adiciona suporte para construções específicas do TypeScript, como genéricos e tipos condicionais.
1.1 Documentando interfaces e tipos
Atenção especial deve ser dada a interfaces e tipos. Eles são o "esqueleto" de um projeto TypeScript. Aqui está um exemplo de uma interface bem documentada:
/** * Representa um usuário do sistema. */interface User { /** Identificador único do usuário */ id: string; /** Nome completo do usuário */ name: string; /** Endereço de email (deve ser único) */ email: string; /** Data do último login no sistema (opcional) */ lastLogin?: Date; /** Papel do usuário no sistema */ role: 'admin' | 'user' | 'moderator';}Observe: cada parâmetro da interface tem seu próprio comentário /** ... */. Isso permite que a IDE (por exemplo, VS Code) mostre dicas ao usar esta interface.
2. Técnicas avançadas: genéricos e tipos condicionais
TypeScript é famoso por seu sistema de tipos, e a documentação deve refletir sua complexidade. Isso é especialmente verdadeiro para genéricos (generic types) e tipos condicionais (conditional types).
Vejamos um exemplo de genérico com documentação:
/** * Cria um array com um único elemento do tipo T. * @template T - Tipo do elemento que será colocado no array * @param item - Elemento a ser encapsulado * @returns Array contendo o elemento passado */function wrapInArray<T>(item: T): T[] { return [item];}A tag @template indica explicitamente o que é T. Isso é especialmente útil quando há vários genéricos ou eles têm uma relação complexa.
Para tipos condicionais, a documentação se torna ainda mais importante. Exemplo:
/** * Extrai o tipo de valor de uma Promise, se uma Promise for passada. * Caso contrário, retorna o tipo original. * @template T - Tipo que pode ser uma Promise ou não * @example * // Para Promise<number> retorna number * type Result = UnwrapPromise<Promise<number>>; // number