desenvolvimento

TypeScript: Dicas avançadas para desenvolvedores

Ricardo Laurito

Ricardo Laurito

UI/UX Designer e Desenvolvedor Web especializado em React e Next

5 ene 2025 4 min de leitura
HomeBlogdesenvolvimento

TypeScript: Dicas avançadas para desenvolvedores

TypeScript oferece muitas funcionalidades avançadas que podem melhorar sua produtividade. Vamos explorar algumas dicas que todo desenvolvedor deveria conhecer.

1. Utility Types

O TypeScript possui vários utility types que facilitam manipulações comuns:

interface User {
  id: string;
  name: string;
  email: string;
  password: string;
}

// Tornar todas as propriedades opcionais
type PartialUser = Partial<User>;

// Selecionar apenas algumas propriedades
type PublicUser = Pick<User, 'id' | 'name' | 'email'>;

// Omitir propriedades específicas
type SafeUser = Omit<User, 'password'>;

// Tornar propriedades obrigatórias
type RequiredUser = Required<PartialUser>;

2. Conditional Types

Crie tipos que dependem de condições:

type NonNullable<T> = T extends null | undefined ? never : T;

type ApiResponse<T> = T extends string
  ? { message: T }
  : T extends number
  ? { count: T }
  : { data: T };

// Exemplo de uso
type StringResponse = ApiResponse<string>; // { message: string }
type NumberResponse = ApiResponse<number>; // { count: number }
type ObjectResponse = ApiResponse<User>; // { data: User }

3. Template Literal Types

Combine strings de forma type-safe:

type EventName = 'click' | 'focus' | 'blur';
type ElementId = 'button' | 'input' | 'form';

type ElementEvent = `${ElementId}:${EventName}`;
// Resultado: 'button:click' | 'button:focus' | 'button:blur' | 'input:click' | ...

// Uso prático
function addEventListener(event: ElementEvent, handler: () => void) {
  // implementação
}

addEventListener('button:click', () => {}); // ✅ Válido
addEventListener('invalid:event', () => {}); // ❌ Erro de tipo

4. Mapped Types

Transforme tipos existentes:

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;

type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

interface User {
  name: string;
  age: number;
}

type UserGetters = Getters<User>;
// Resultado: { getName: () => string; getAge: () => number; }

5. Discriminated Unions

Crie tipos seguros para diferentes estados:

type LoadingState = {
  status: 'loading';
};

type SuccessState = {
  status: 'success';
  data: User[];
};

type ErrorState = {
  status: 'error';
  error: string;
};

type AsyncState = LoadingState | SuccessState | ErrorState;

function handleState(state: AsyncState) {
  switch (state.status) {
    case 'loading':
      return 'Carregando...';
    case 'success':
      return `${state.data.length} usuários encontrados`;
    case 'error':
      return `Erro: ${state.error}`;
  }
}

6. Assertion Functions

Crie funções que fazem assertions:

function assertIsNumber(value: unknown): asserts value is number {
  if (typeof value !== 'number') {
    throw new Error('Expected number');
  }
}

function processValue(input: unknown) {
  assertIsNumber(input);
  // TypeScript agora sabe que input é number
  return input.toFixed(2);
}

7. const assertions

Preserve tipos literais:

// Sem const assertion
const config = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
}; // Tipo: { apiUrl: string; timeout: number; }

// Com const assertion
const configConst = {
  apiUrl: 'https://api.example.com',
  timeout: 5000
} as const; // Tipo: { readonly apiUrl: "https://api.example.com"; readonly timeout: 5000; }

// Para arrays
const fruits = ['apple', 'banana'] as const;
// Tipo: readonly ["apple", "banana"]

8. Namespace Patterns

Organize código com namespaces:

namespace API {
  export interface User {
    id: string;
    name: string;
  }

  export namespace Users {
    export async function getAll(): Promise<User[]> {
      // implementação
    }

    export async function getById(id: string): Promise<User> {
      // implementação
    }
  }
}

// Uso
const users = await API.Users.getAll();

9. Branded Types

Crie tipos distintos para valores similares:

type UserId = string & { __brand: 'UserId' };
type ProductId = string & { __brand: 'ProductId' };

function createUserId(id: string): UserId {
  return id as UserId;
}

function getUser(id: UserId) {
  // implementação
}

const userId = createUserId('123');
const productId = '456' as ProductId;

getUser(userId); // ✅ Válido
getUser(productId); // ❌ Erro de tipo

10. Configuração avançada do tsconfig.json

Otimize seu projeto:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "paths": {
      "@/*": ["./src/*"],
      "@/components/*": ["./src/components/*"],
      "@/utils/*": ["./src/utils/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Conclusão

Essas dicas avançadas do TypeScript podem transformar a forma como você escreve código, oferecendo mais segurança, expressividade e produtividade. Pratique essas técnicas em seus projetos e veja a diferença!

Lembre-se: TypeScript é uma ferramenta poderosa, mas use com moderação. Nem sempre a solução mais complexa é a melhor.

Ricardo Laurito

Sobre o Autor

UI/UX Designer e Desenvolvedor Web especializado em React e Next.js

Comentários

0 Comentários

Seja o primeiro a comentar neste artigo.