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.

Comentários
0 ComentáriosSeja o primeiro a comentar neste artigo.