<h2>Entendendo o Contexto: Por Que Migrar para TypeScript?</h2>
<p>JavaScript é uma linguagem dinâmica e flexível, características que a tornaram popular, mas também geradora de bugs difíceis de rastrear em projetos grandes. TypeScript resolve esse problema ao adicionar verificação de tipos estática durante o desenvolvimento, permitindo que você capture erros antes da execução. Quando você trabalha em um projeto real com múltiplos desenvolvedores, refatorações frequentes ou código legado, essa segurança se torna essencial.</p>
<p>A migração não precisa ser um evento traumático onde você para tudo e reescreve o projeto. Projetos maduros podem fazer essa transição de forma gradual, permitindo que arquivos TypeScript coexistam com JavaScript. Essa estratégia reduz risco, mantém a produtividade e permite que o time aprenda TypeScript naturalmente. Nesta aula, você aprenderá exatamente como fazer isso em um projeto real.</p>
<h2>Fase 1: Preparação e Configuração do Ambiente</h2>
<h3>Instalando TypeScript e Configurando o Projeto</h3>
<p>Começamos adicionando TypeScript ao seu projeto. Você não precisa remover nada do JavaScript existente:</p>
<pre><code class="language-bash">npm install --save-dev typescript
npx tsc --init</code></pre>
<p>Isso cria um arquivo <code>tsconfig.json</code> que controla como o TypeScript compila seu código. Para um projeto em migração, configure-o de forma permissiva inicialmente:</p>
<pre><code class="language-json">{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["ES2020"],
"outDir": "./dist",
"rootDir": "./src",
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"moduleResolution": "node"
},
"include": ["src/*/"],
"exclude": ["node_modules", "dist"]
}</code></pre>
<p>Note que <code>"strict": false</code> inicialmente. Isso permite que arquivos TypeScript e JavaScript coexistam sem erros. Conforme ganhar confiança, você aumenta gradualmente o nível de rigor.</p>
<h3>Integrando com seu Build System</h3>
<p>Se você usa Webpack, Vite ou outro bundler, precise adicionar o loader TypeScript:</p>
<pre><code class="language-bash">npm install --save-dev ts-loader</code></pre>
<p>Para Webpack, atualize seu <code>webpack.config.js</code>:</p>
<pre><code class="language-javascript">module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
};</code></pre>
<h2>Fase 2: Migração Gradual de Arquivos</h2>
<h3>Começando com Módulos Isolados</h3>
<p>A chave para migração bem-sucedida é começar com arquivos que têm poucas dependências. Identifique módulos utilitários ou helpers que outras partes do código usam, mas que não dependem de muitos outros arquivos.</p>
<p>Vamos converter um arquivo de utilitários. Antes, em JavaScript puro:</p>
<pre><code class="language-javascript">// utils.js
export function formatCurrency(value) {
return '$' + (value / 100).toFixed(2);
}
export function calculateTax(amount, taxRate) {
return amount * (taxRate / 100);
}
export function parseDate(dateString) {
return new Date(dateString);
}</code></pre>
<p>Migre para TypeScript adicionando tipos explícitos:</p>
<pre><code class="language-typescript">// utils.ts
export function formatCurrency(value: number): string {
return '$' + (value / 100).toFixed(2);
}
export function calculateTax(amount: number, taxRate: number): number {
return amount * (taxRate / 100);
}
export function parseDate(dateString: string): Date {
return new Date(dateString);
}</code></pre>
<p>O compilador agora garante que <code>formatCurrency</code> recebe apenas números. Se alguém chamar <code>formatCurrency("100")</code>, o TypeScript avisará durante o desenvolvimento.</p>
<h3>Importações Seguras em Código JavaScript</h3>
<p>Seu código JavaScript ainda pode importar de módulos TypeScript sem problemas:</p>
<pre><code class="language-javascript">// calculator.js
import { formatCurrency, calculateTax } from './utils';
const total = calculateTax(1000, 10);
console.log(formatCurrency(total));</code></pre>
<p>O TypeScript compila para JavaScript normal, então essa importação funciona perfeitamente.</p>
<h2>Fase 3: Tipagem Avançada e Refatoração</h2>
<h3>Definindo Tipos Complexos</h3>
<p>Conforme você migra mais arquivos, crie tipos reutilizáveis. Vamos imaginar uma aplicação de e-commerce:</p>
<pre><code class="language-typescript">// types.ts
export type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered';
export interface Product {
id: string;
name: string;
price: number;
quantity: number;
}
export interface Order {
id: string;
products: Product[];
status: OrderStatus;
createdAt: Date;
totalAmount: number;
}
export interface Customer {
id: string;
email: string;
name: string;
orders: Order[];
}</code></pre>
<p>Agora qualquer arquivo que trabalhe com pedidos tem segurança de tipo:</p>
<pre><code class="language-typescript">// orderService.ts
import { Order, Product, OrderStatus } from './types';
export class OrderService {
calculateTotal(products: Product[]): number {
return products.reduce((sum, p) => sum + p.price * p.quantity, 0);
}
updateStatus(order: Order, newStatus: OrderStatus): Order {
return {
...order,
status: newStatus,
};
}
filterByStatus(orders: Order[], status: OrderStatus): Order[] {
return orders.filter(o => o.status === status);
}
}</code></pre>
<p>Se um desenvolvedor tentar passar um status inválido, o TypeScript reclama imediatamente.</p>
<h3>Genéricos para Reutilização</h3>
<p>TypeScript oferece genéricos para criar funções e classes que funcionam com qualquer tipo, mas mantêm segurança:</p>
<pre><code class="language-typescript">// repository.ts
export class Repository<T> {
private items: T[] = [];
add(item: T): void {
this.items.push(item);
}
findById(id: string, idField: keyof T): T | undefined {
return this.items.find(item => item[idField] === id);
}
getAll(): T[] {
return [...this.items];
}
remove(id: string, idField: keyof T): void {
this.items = this.items.filter(item => item[idField] !== id);
}
}</code></pre>
<p>Reutilize essa classe para qualquer entidade:</p>
<pre><code class="language-typescript">// main.ts
import { Repository } from './repository';
import { Order, Customer } from './types';
const orderRepository = new Repository<Order>();
const customerRepository = new Repository<Customer>();
const order: Order = {
id: '123',
products: [],
status: 'pending',
createdAt: new Date(),
totalAmount: 0,
};
orderRepository.add(order);
const found = orderRepository.findById('123', 'id');</code></pre>
<h2>Fase 4: Tratamento de Dependências Externas</h2>
<h3>Tipando Bibliotecas sem Tipos</h3>
<p>Nem todas as bibliotecas npm têm tipos TypeScript. Para as que não têm, você cria um arquivo de declaração <code>.d.ts</code>:</p>
<pre><code class="language-typescript">// types/legacy-lib.d.ts
declare module 'legacy-lib' {
export function process(data: any): string;
export class Handler {
execute(input: string): Promise<void>;
}
}</code></pre>
<p>Agora você pode usar a biblioteca com segurança de tipo:</p>
<pre><code class="language-typescript">// worker.ts
import { process, Handler } from 'legacy-lib';
const result: string = process(someData);
const handler = new Handler();
await handler.execute(result);</code></pre>
<h3>Consultando Tipos de Bibliotecas Modernas</h3>
<p>Muitas bibliotecas modernas já incluem tipos. Se usar <code>axios</code>, por exemplo:</p>
<pre><code class="language-typescript">// api.ts
import axios, { AxiosResponse } from 'axios';
export interface ApiResponse<T> {
data: T;
status: number;
}
export async function fetchUser(id: string): Promise<ApiResponse<{ name: string; email: string }>> {
const response: AxiosResponse<{ name: string; email: string }> = await axios.get(
/api/users/${id}
);
return {
data: response.data,
status: response.status,
};
}</code></pre>
<p>TypeScript automaticamente infere e valida que o tipo retornado corresponde ao esperado.</p>
<h2>Fase 5: Aumentando o Rigor Gradualmente</h2>
<h3>Ativando Verificações Estritas</h3>
<p>Depois que a maioria do código foi migrado, ative as verificações estritas no <code>tsconfig.json</code>:</p>
<pre><code class="language-json">{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"alwaysStrict": true
}
}</code></pre>
<p>Isso obriga a tipagem explícita em todos os lugares. Inicialmente, você verá muitos erros — isso é esperado e produtivo. Resolva-os arquivo por arquivo.</p>
<h3>Tratando Valores Nulos e Indefinidos</h3>
<p>Uma vantagem crítica do <code>strictNullChecks</code> é forçar você a lidar explicitamente com valores que podem ser nulos:</p>
<pre><code class="language-typescript">// Sem strict: compila, mas pode quebrar em runtime
function getName(user) {
return user.name.toUpperCase();
}
// Com strict: força você a verificar
function getName(user: { name?: string }): string {
return user.name?.toUpperCase() ?? 'UNKNOWN';
}</code></pre>
<p>Essa pequena mudança previne um dos bugs mais comuns em JavaScript.</p>
<h2>Conclusão</h2>
<p>A migração para TypeScript é um investimento que se paga rapidamente em projetos reais. Você aprendeu que a transição não precisa ser tudo ou nada — começar com módulos isolados, configurar o compilador permissivamente e aumentar gradualmente o rigor é a estratégia profissional. Os três ganhos principais são: <strong>erros capturados cedo durante o desenvolvimento</strong>, <strong>refatorações mais seguras porque o compilador valida</strong> e <strong>documentação viva através dos tipos, que nunca fica desatualizada como comentários tradicionais</strong>.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.typescriptlang.org/docs/" target="_blank" rel="noopener noreferrer">TypeScript Official Documentation</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/2/types-from-types.html" target="_blank" rel="noopener noreferrer">TypeScript Handbook - Types</a></li>
<li><a href="https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html" target="_blank" rel="noopener noreferrer">Migration Guide - TypeScript</a></li>
<li><a href="https://effectivetypescript.com/" target="_blank" rel="noopener noreferrer">Effective TypeScript by Dan Vanderkam</a></li>
<li><a href="https://www.youtube.com/playlist?list=PL4cUxeGkcC9gUgr39Q_yD6SE-7YCKXoversimplified" target="_blank" rel="noopener noreferrer">Learn TypeScript - The Net Ninja</a></li>
</ul>
<p><!-- FIM --></p>