TypeScript: tipos que acompanham o código.
Checklist final: strict: true, evitar any, preferir inferência, modelar dados com tipos antes de escrever lógica.
O módulo converteu os quatro arquivos JavaScript do blog — utils.js, api.js, ui.js e main.js — para TypeScript. O blog não mudou visualmente. O que mudou é que erros de tipo, que antes só apareceriam em runtime (e frequentemente no browser do usuário), agora aparecem no editor durante o desenvolvimento. Esta lição consolida os conceitos percorridos e estabelece o checklist para o próximo módulo.
O que mudou no blog
A migração de .js para .ts foi incremental — cada arquivo ganhou tipos sem mudar a lógica. O types.ts foi o ponto de partida: as interfaces Artigo, Autor e Tag, e os type aliases Tema e StatusArtigo. Com esses tipos definidos, os demais módulos os importaram e o compilador passou a verificar toda interação com dados de artigos.
// utils.js — JavaScript original
function calcularTempoLeitura(palavras) {
return Math.ceil(palavras / 238);
}
// utils.ts — TypeScript
function calcularTempoLeitura(palavras: number): number {
return Math.ceil(palavras / 238);
}
// a diferença é pequena no código, mas o efeito é grande:
// chamar calcularTempoLeitura("muito texto") agora é erro de compilação
// chamar calcularTempoLeitura() sem argumento também é erro
// o editor mostra o tipo esperado ao digitar a chamada
// api.ts — o mais crítico
async function buscarArtigos(): Promise<Artigo[]> {
const response = await fetch("/artigos.json");
if (!response.ok) throw new Error(`Erro ${response.status}`);
return response.json() as Promise<Artigo[]>;
}
// agora qualquer código que usa buscarArtigos() sabe que recebe Artigo[]
// acessar .descricao em vez de .titulo? erro de compilação
// passar o resultado para uma função que espera Autor[]? erro de compilação O compilador se tornou o guardião da consistência entre módulos: se você alterar a interface Artigo (adicionar um campo, mudar um tipo), todos os lugares que usam Artigo recebem erros de compilação até serem atualizados. Um refactor que antes exigia grep manual agora tem cobertura automática.
Checklist TypeScript
Estas práticas aparecem ao longo do módulo com razões específicas — cada uma protege contra uma classe de erro concreta:
// ✅ strict: true no tsconfig.json
// sem strict, null e undefined passam sem verificação e any aparece silenciosamente
// ✅ interfaces para todos os objetos de domínio — types.ts
export interface Artigo {
id: number;
titulo: string;
publicadoEm: string | null; // null declarado explicitamente — não é surpresa
readonly slug: string; // readonly — o compilador impede reatribuição acidental
}
// ✅ anote nas bordas — parâmetros de funções exportadas
export function formatarData(dateString: string): string { /* ... */ }
export function renderizarCard(artigo: Artigo, curtido: boolean): string { /* ... */ }
// ✅ infira no interior — variáveis temporárias e callbacks
const publicados = artigos.filter(a => a.publicado); // Artigo[] — inferido
const titulos = publicados.map(a => a.titulo); // string[] — inferido
// ✅ unknown no catch — com strict, o padrão moderno
try {
await buscarArtigos();
} catch (erro) {
if (erro instanceof Error) {
exibirNotificacao(erro.message);
}
}
// ✅ as const para configurações e conjuntos de valores
const STATUS = { Rascunho: "rascunho", Publicado: "publicado" } as const;
type Status = typeof STATUS[keyof typeof STATUS]; // "rascunho" | "publicado"
// ✅ discriminated unions para estados
type EstadoCarregamento =
| { status: "carregando" }
| { status: "sucesso"; artigos: Artigo[] }
| { status: "erro"; mensagem: string };
// ✅ tipos utilitários em vez de duplicar interfaces
type FormularioEdicao = Partial<Omit<Artigo, "id" | "slug" | "curtidas">>;
// ✅ evitar any — sempre há uma alternativa melhor
// any → unknown (dados desconhecidos)
// any → generic <T> (código reutilizável)
// any → tipo específico (quando você sabe o que é) A relação com o módulo de React
O TypeScript aprendido aqui continua no React — os mesmos conceitos, aplicados a um novo contexto. As interfaces viram tipos de props, os generics aparecem em hooks, os discriminated unions descrevem estados de componente:
// no blog:
interface Artigo { id: number; titulo: string; /* ... */ }
function renderizarCard(artigo: Artigo): string { /* ... */ }
// no React — a mesma lógica, com JSX:
interface Props {
artigo: Artigo;
curtido: boolean;
onCurtir: (id: number) => void;
}
function CardArtigo({ artigo, curtido, onCurtir }: Props) {
return (
<article>
<h2>{artigo.titulo}</h2>
<button onClick={() => onCurtir(artigo.id)}>
{curtido ? "❤️" : "🤍"}
</button>
</article>
);
}
// o useState é genérico — inferência automática
const [curtidos, setCurtidos] = useState<number[]>([]);
// curtidos é number[] — o mesmo tipo que localStorage.getItem no blog O modelo mental muda de “manipular o DOM diretamente” para “descrever como a UI deve ser dado o estado”. O TypeScript acompanha essa mudança sem exigir reaprendizado — você continua usando interface, type, generics e unions. O que muda é o destino: em vez de el.textContent = artigo.titulo, você retorna <h2>{artigo.titulo}</h2> de um componente.
Resumo
strict: trueé o ponto de partida — habilitastrictNullChecksenoImplicitAny, sem os quais o TypeScript não detecta os erros mais comuns.- Interfaces de domínio (
Artigo,Autor,Tag) são a fonte da verdade — defina-as primeiro, escreva a lógica depois. Quando a interface muda, o compilador aponta todos os chamadores desatualizados. - Anote nas bordas (parâmetros de funções exportadas, respostas de API), infira no interior (variáveis temporárias, callbacks de
map/filter). unknownem vez deanypara dados externos — exige narrowing ou cast explícito, mantendo a proteção.as constpara configurações e conjuntos de valores — cria tipos literais ereadonlycom zero custo em runtime.- Discriminated unions para estados de carregamento —
{ status: "carregando" } | { status: "sucesso"; dados: T } | { status: "erro"; mensagem: string }. - Tipos utilitários (
Partial,Omit,Pick,Record,ReturnType) para derivar variações de interfaces sem duplicar. - React é o próximo módulo: os mesmos tipos TypeScript, aplicados a props de componentes, hooks tipados e estado declarativo.
Por que strict: true é a primeira configuração a ativar em um projeto novo?
Qual é a relação entre interface Artigo e as funções que recebem Artigo como parâmetro?
Quando você deve usar unknown em vez de any?
O que significa 'anote nas bordas, infira no meio'?
Aula concluída
Quase lá.