Arquitetura softwareFrontend webTypeScriptGenerics Avançado
Utility Types
Baixar PDFPartial, Pick, Omit, Record, Extract, Exclude, ReturnType, Parameters — tipos utilitários embutidos e customizados.
Utility Types em TypeScript
TypeScript vem com um conjunto de tipos utilitários (utility types) que transformam tipos existentes. São como funções, mas para tipos.
Tipos utilitários embutidos
Partial<T> — Torna todas as propriedades opcionais
interface User {
id: string;
name: string;
email: string;
age: number;
}
type PartialUser = Partial<User>;
// { id?: string; name?: string; email?: string; age?: number; }
// Uso: updates parciais
function updateUser(id: string, data: Partial<User>): Promise<User> {
// só precisa passar os campos que quer alterar
return db.users.update(id, data);
}
updateUser('1', { name: 'Novo Nome' }); // ✅ só altera o nomeRequired<T> — Torna todas as propriedades obrigatórias
type Config = {
host?: string;
port?: number;
database?: string;
};
type RequiredConfig = Required<Config>;
// { host: string; port: number; database: string; }
// Uso: garantir que configuração está completa
function startServer(config: Required<Config>) {
// TS garante que host, port e database existem
}Pick<T, K> — Seleciona propriedades específicas
type UserPublic = Pick<User, 'id' | 'name'>;
// { id: string; name: string; }
// Uso: DTOs públicos que expõem menos dados
app.get('/api/users/:id', async (req, res) => {
const user = await db.users.findById(req.params.id);
const publicData: Pick<User, 'id' | 'name' | 'email'> = {
id: user.id,
name: user.name,
email: user.email,
};
res.json(publicData);
});Omit<T, K> — Remove propriedades específicas
type CreateUserDto = Omit<User, 'id'>;
// { name: string; email: string; age: number; }
// id é removido — o banco gera
// Uso: criar sem ID
async function createUser(data: CreateUserDto): Promise<User> {
const id = generateId();
return db.users.create({ id, ...data });
}Record<K, V> — Cria tipo de objeto com chaves e valores fixos
type StatusMap = Record<string, string>;
// { [key: string]: string }
// Mais específico
type HttpCodes = Record<'ok' | 'created' | 'notFound' | 'error', number>;
const codes: HttpCodes = {
ok: 200,
created: 201,
notFound: 404,
error: 500,
};
// Frontend — configuração de rotas
type RouteConfig = Record<string, { path: string; component: React.ComponentType }>;Extract<T, U> e Exclude<T, U> — Filtra union types
type AllStatus = 'active' | 'inactive' | 'pending' | 'deleted' | 'banned';
type ActiveStatuses = Extract<AllStatus, 'active' | 'pending'>;
// 'active' | 'pending'
type NonDeletedStatuses = Exclude<AllStatus, 'deleted' | 'banned'>;
// 'active' | 'inactive' | 'pending'ReturnType<T> e Parameters<T> — Deriva de funções
function getUser(id: string): { name: string; email: string } {
return db.users.findById(id);
}
type UserReturn = ReturnType<getUser>;
// { name: string; email: string }
type UserParams = Parameters<getUser>;
// [id: string]
// Uso: manter tipos sincronizados automaticamente
type FetchResult = ReturnType<typeof fetchUser>;
// Se fetchUser mudar o retorno, FetchResult atualiza sozinhoAwaited<T> — Extrai o tipo de uma Promise
type UserPromise = Promise<User>;
type UserResolved = Awaited<UserPromise>;
// User
// Útil para tipar o resultado de operações async sem duplicar
async function loadDashboard() {
const user = await fetchUser(); // User
const orders = await fetchOrders(); // Order[]
const stats = await fetchStats(); // Stats
return { user, orders, stats };
}
type DashboardData = Awaited<ReturnType<typeof loadDashboard>>;
// { user: User; orders: Order[]; stats: Stats }Utility types customizados
Nullable<T> — Adiciona null e undefined
type Nullable<T> = T | null | undefined;
function findUser(id: string): Nullable<User> {
return db.users.findById(id) ?? undefined;
}DeepPartial<T> — Partial recursivo
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
interface Config {
server: {
host: string;
port: number;
ssl: {
enabled: boolean;
cert: string;
};
};
db: {
url: string;
poolSize: number;
};
}
type PartialConfig = DeepPartial<Config>;
// server.ssl.enabled pode ser definido sem definir server.host
const override: PartialConfig = {
server: { ssl: { enabled: true } }, // ✅ TS aceita — não precisa definir host nem port
};NonNullableProperties<T> — Remove null de todas as propriedades
type NonNullableProperties<T> = {
[K in keyof T]: NonNullable<T[K]>;
};
interface FormState {
name: string | null;
email: string | null;
age: number | null;
}
type ValidatedForm = NonNullableProperties<FormState>;
// { name: string; email: string; age: number; }
function validateForm(form: FormState): ValidatedForm {
if (!form.name || !form.email || !form.age) {
throw new Error('Todos os campos são obrigatórios');
}
return form as ValidatedForm; // ✅ TS sabe que nada é null
}