Voltar para o Blog
Anúncio

TypeScript em 2025: Por que 80% das Vagas Exigem e Como Dominar

Olá HaWkers, se você ainda está usando JavaScript puro em 2025, preciso ser direto: você está ficando para trás. TypeScript não é mais uma "tecnologia da moda" - é o novo padrão da indústria.

A adoção do TypeScript explodiu de 12% em 2017 para 35% em 2024, e em 2025 cerca de 80% das vagas mid-level e senior listam TypeScript como requisito obrigatório. Não opcional. Obrigatório.

Por que essa mudança drástica aconteceu?

A História de Como TypeScript Venceu

TypeScript foi lançado pela Microsoft em 2012, mas durante anos foi visto como "JavaScript com tipos chatos" por muitos desenvolvedores. O que mudou?

2017-2019: A Virada

Três fatores convergiram:

  1. Angular 2+ foi totalmente reescrito em TypeScript
  2. VS Code ofereceu suporte excepcional para TypeScript out of the box
  3. React começou a adotar TypeScript em sua documentação oficial

Mas o verdadeiro ponto de virada foi quando grandes empresas começaram a reportar redução de 15-30% em bugs de produção após migrar para TypeScript.

// Exemplo real: Bug que TypeScript teria prevenido
// JavaScript - Compila sem erros
function calculateDiscount(price, discount) {
  return price - (price * discount);
}

// Código parece correto, mas...
calculateDiscount('100', 0.2);  // Resultado: "1000.2" (bug!)
calculateDiscount(100, '20%');  // Resultado: NaN (bug!)

// TypeScript - Erros em tempo de desenvolvimento
function calculateDiscount(price: number, discount: number): number {
  return price - (price * discount);
}

calculateDiscount('100', 0.2);  // ❌ Error: Argument of type 'string' is not assignable
calculateDiscount(100, '20%');  // ❌ Error: Argument of type 'string' is not assignable

// Código correto e type-safe
const finalPrice = calculateDiscount(100, 0.2); // ✅ OK: 80
Anúncio

Por Que Empresas Exigem TypeScript em 2025

1. Redução Drástica de Bugs

// Exemplo: API response handling
// JavaScript - Propenso a erros em runtime
async function getUser(id) {
  const response = await fetch(`/api/users/${id}`);
  const user = await response.json();

  // Se a API mudar, você só descobre em produção
  console.log(user.fullName); // Pode explodir se field não existir
  return user;
}

// TypeScript - Erros em tempo de desenvolvimento
interface User {
  id: string;
  firstName: string;
  lastName: string;
  email: string;
  role: 'admin' | 'user';
  createdAt: string;
}

interface ApiResponse<T> {
  data: T;
  error?: string;
  meta: {
    timestamp: number;
    requestId: string;
  };
}

async function getUser(id: string): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  const result: ApiResponse<User> = await response.json();

  if (result.error) {
    throw new Error(result.error);
  }

  const user = result.data;

  // ❌ TypeScript error: Property 'fullName' does not exist on type 'User'
  // console.log(user.fullName);

  // ✅ Correto - TypeScript sugere os campos disponíveis
  console.log(`${user.firstName} ${user.lastName}`);

  return user;
}

2. Refatoração Segura em Grandes Código

Imagine renomear uma propriedade usada em 50 arquivos diferentes. Em JavaScript, você torce para sua busca-e-substitui funcionar. Em TypeScript, o compilador encontra todos os usos.

// Before: interface User com campo 'role'
interface User {
  id: string;
  email: string;
  role: string;  // ← Vamos mudar isso
}

// Depois: mudamos para um union type mais específico
interface User {
  id: string;
  email: string;
  permissions: 'admin' | 'user' | 'moderator';  // ← Renomeado e melhorado
}

// TypeScript automaticamente marca TODOS os lugares que precisam ser atualizados
function checkAccess(user: User) {
  // ❌ Error: Property 'role' does not exist on type 'User'
  if (user.role === 'admin') {
    return true;
  }

  // ✅ Correto após refatoração
  if (user.permissions === 'admin') {
    return true;
  }
}

3. Documentação Viva no Código

// TypeScript serve como documentação sempre atualizada
/**
 * Cria um novo usuário no sistema
 *
 * @throws {ValidationError} Se os dados são inválidos
 * @throws {DuplicateEmailError} Se email já existe
 */
async function createUser(
  data: {
    email: string;
    password: string;
    firstName: string;
    lastName: string;
    dateOfBirth?: Date;  // Opcional
  }
): Promise<User> {
  // Implementação...
}

// O editor mostra exatamente o que você precisa passar
createUser({
  email: 'john@example.com',
  // ← O autocomplete mostra os campos obrigatórios e opcionais
  password: 'secure123',
  firstName: 'John',
  lastName: 'Doe'
});
Anúncio

Conceitos Avançados que Você Precisa Dominar

Generics: O Poder da Reutilização Type-Safe

// Exemplo: Criando um cache genérico type-safe
class Cache<T> {
  private storage = new Map<string, {
    data: T;
    expiresAt: number;
  }>();

  set(key: string, value: T, ttl: number = 3600): void {
    this.storage.set(key, {
      data: value,
      expiresAt: Date.now() + (ttl * 1000)
    });
  }

  get(key: string): T | null {
    const item = this.storage.get(key);

    if (!item) return null;

    if (Date.now() > item.expiresAt) {
      this.storage.delete(key);
      return null;
    }

    return item.data;
  }

  // Generic method para transformar valores
  transform<R>(key: string, transformer: (value: T) => R): R | null {
    const value = this.get(key);
    return value ? transformer(value) : null;
  }
}

// Uso type-safe
interface User {
  id: string;
  name: string;
  email: string;
}

const userCache = new Cache<User>();

userCache.set('user:123', {
  id: '123',
  name: 'John Doe',
  email: 'john@example.com'
});

const user = userCache.get('user:123');  // Type: User | null

// ✅ TypeScript sabe que user pode ser null
if (user) {
  console.log(user.email);  // ← Autocomplete funciona!
}

// Transform com type inference
const userName = userCache.transform('user:123', user => user.name);
// Type: string | null ← TypeScript inferiu automaticamente!

Utility Types: Ferramentas Poderosas Built-in

interface Product {
  id: string;
  name: string;
  price: number;
  description: string;
  stock: number;
  category: string;
  createdAt: Date;
  updatedAt: Date;
}

// Partial - Todos os campos opcionais
type ProductUpdate = Partial<Product>;

async function updateProduct(id: string, updates: ProductUpdate) {
  // Pode passar qualquer combinação de campos
  // { price: 99.99 } ✅
  // { name: 'New Name', stock: 10 } ✅
}

// Pick - Selecionar apenas campos específicos
type ProductPreview = Pick<Product, 'id' | 'name' | 'price'>;

function displayProductCard(product: ProductPreview) {
  // Só tem acesso a id, name e price
  console.log(product.name, product.price);
  // product.description ← ❌ Error: Property does not exist
}

// Omit - Todos exceto os especificados
type ProductCreate = Omit<Product, 'id' | 'createdAt' | 'updatedAt'>;

async function createProduct(data: ProductCreate): Promise<Product> {
  // Não precisa passar id, createdAt, updatedAt
  // Sistema gera automaticamente
  return {
    ...data,
    id: crypto.randomUUID(),
    createdAt: new Date(),
    updatedAt: new Date()
  };
}

// Record - Criar objetos com chaves específicas
type ProductsByCategory = Record<string, Product[]>;

const groupedProducts: ProductsByCategory = {
  'electronics': [/* produtos */],
  'books': [/* produtos */],
  'clothing': [/* produtos */]
};

// Readonly - Imutabilidade
type ImmutableProduct = Readonly<Product>;

const product: ImmutableProduct = {
  /* ... */
};

// product.price = 999; ← ❌ Error: Cannot assign to 'price'

Conditional Types: Lógica em Nível de Tipos

// Exemplo avançado: Tipos condicionais para API responses
type ApiResponse<T> = T extends { error: any }
  ? { success: false; error: string }
  : { success: true; data: T };

// Extrair tipos de arrays
type ArrayElement<T> = T extends (infer E)[] ? E : never;

type Numbers = ArrayElement<number[]>;  // number
type Strings = ArrayElement<string[]>;  // string

// Extrair tipo de retorno de função
type ReturnTypeOf<T> = T extends (...args: any[]) => infer R ? R : never;

async function getUsers() {
  return [{ id: '1', name: 'John' }];
}

type Users = ReturnTypeOf<typeof getUsers>;
// Type: Promise<{ id: string; name: string; }[]>

// Unwrap Promise
type Awaited<T> = T extends Promise<infer U> ? U : T;

type UnwrappedUsers = Awaited<Users>;
// Type: { id: string; name: string; }[]
Anúncio

Padrões Reais de Produção

1. Type Guards para Validação em Runtime

// Type guard personalizado
interface Dog {
  type: 'dog';
  bark: () => void;
}

interface Cat {
  type: 'cat';
  meow: () => void;
}

type Pet = Dog | Cat;

// Type guard function
function isDog(pet: Pet): pet is Dog {
  return pet.type === 'dog';
}

function handlePet(pet: Pet) {
  if (isDog(pet)) {
    pet.bark();  // ✅ TypeScript sabe que é Dog
  } else {
    pet.meow();  // ✅ TypeScript sabe que é Cat
  }
}

// Type guard com validação de API
function isValidUser(data: unknown): data is User {
  return (
    typeof data === 'object' &&
    data !== null &&
    'id' in data &&
    'email' in data &&
    typeof (data as any).email === 'string'
  );
}

async function fetchUser(id: string): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  const data = await response.json();

  if (!isValidUser(data)) {
    throw new Error('Invalid user data from API');
  }

  return data;  // ✅ TypeScript sabe que é User
}

2. Builder Pattern com TypeScript

// Fluent API type-safe
class QueryBuilder<T> {
  private conditions: string[] = [];
  private orderField?: keyof T;
  private limitValue?: number;

  where(field: keyof T, operator: string, value: any): this {
    this.conditions.push(`${String(field)} ${operator} ${value}`);
    return this;
  }

  orderBy(field: keyof T, direction: 'ASC' | 'DESC' = 'ASC'): this {
    this.orderField = field;
    return this;
  }

  limit(n: number): this {
    this.limitValue = n;
    return this;
  }

  build(): string {
    let query = `SELECT * FROM table`;

    if (this.conditions.length > 0) {
      query += ` WHERE ${this.conditions.join(' AND ')}`;
    }

    if (this.orderField) {
      query += ` ORDER BY ${String(this.orderField)}`;
    }

    if (this.limitValue) {
      query += ` LIMIT ${this.limitValue}`;
    }

    return query;
  }
}

// Uso type-safe
interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

const query = new QueryBuilder<User>()
  .where('age', '>', 18)
  .where('email', 'LIKE', '%@example.com')
  .orderBy('name', 'ASC')  // ← Autocomplete só sugere campos válidos!
  .limit(10)
  .build();

// .orderBy('invalidField') ← ❌ Error: Argument not assignable
Anúncio

Como Aprender TypeScript em 2025

Roadmap de 30 Dias

// Semana 1: Fundamentos
const week1Topics = [
  'Tipos básicos (string, number, boolean, array)',
  'Interfaces vs Types',
  'Union types e intersection types',
  'Type annotations e type inference',
  'Functions e seus tipos'
];

// Semana 2: Intermediário
const week2Topics = [
  'Generics',
  'Utility types (Partial, Pick, Omit, Record)',
  'Type guards',
  'Enums e const assertions',
  'Modules e namespaces'
];

// Semana 3: Avançado
const week3Topics = [
  'Conditional types',
  'Mapped types',
  'Template literal types',
  'Decorators',
  'Type manipulation avançada'
];

// Semana 4: Prática Real
const week4Projects = [
  'Migrar projeto JavaScript existente',
  'Criar API REST type-safe',
  'Implementar state management com tipos',
  'Escrever testes com tipos',
  'Configurar CI/CD com type checking'
];

Recursos Essenciais

  1. TypeScript Handbook (oficial) - Gratuito e completo
  2. TypeScript Exercises - Desafios práticos
  3. Type Challenges - Problemas avançados
  4. Projetos reais - Migre seus projetos pessoais

Erros Comuns que Você Deve Evitar

// ❌ Usar 'any' demais derrota o propósito
function processData(data: any) {
  return data.value;  // Sem type safety
}

// ✅ Use types específicos ou unknown
function processData(data: unknown) {
  if (typeof data === 'object' && data !== null && 'value' in data) {
    return (data as { value: string }).value;
  }
  throw new Error('Invalid data');
}

// ❌ Ignorar erros com @ts-ignore
// @ts-ignore
const result = someFunction();

// ✅ Resolver o problema ou usar assertion consciente
const result = someFunction() as ExpectedType;

// ❌ Tipos muito genéricos
interface Data {
  value: any;
  items: any[];
}

// ✅ Tipos específicos e úteis
interface UserData {
  value: string | number;
  items: User[];
}

O Futuro: TypeScript 6.0 e Além

TypeScript continua evoluindo rapidamente. Recursos futuros incluem:

  • Melhor suporte para decorators (stage 3)
  • Type imports mais inteligentes
  • Performance melhorada para grandes projetos
  • Integração mais profunda com frameworks

Se você quer ver TypeScript em ação em projetos reais, recomendo dar uma olhada em outro artigo: Mercado de Trabalho Dev 2025: As Habilidades Essenciais onde você vai descobrir como TypeScript se encaixa no panorama completo de habilidades necessárias.

Bora pra cima! 🦅

Anúncio
Post anteriorPróximo post

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário