TypeScript: Tipos utilitários do TypeScript
Última atualização: 2026-10-22
O TypeScript inclui mais de uma dúzia de tipos utilitários — eles representam as melhores práticas em programação genérica e permitem realizar conversões de tipos comuns com uma única linha de código.
1. Classe de transformação de propriedades
(1) Parcial — Todas as propriedades passam a ser opcionais
TYPESCRIPT
interface User {
id: number;
name: string;
email: string;
age: number;
}
// Partial Make all properties optional——Suitable for update operations
type PartialUser = Partial<User>;
// { id?: number; name?: string; email?: string; age?: number }
function updateUser(user: User, updates: Partial<User>): User {
return { ...user, ...updates };
}
let user: User = { id: 1, name: "Charlie", email: "xiao@example.com", age: 20 };
let updated = updateUser(user, { age: 21 });
// Update Only age,All other attributes remain unchanged
console.log(updated.age); // 21
console.log(updated.name); // "Charlie"(Unchanged)
(2) Obrigatório — Agora, todas as propriedades são obrigatórias
TYPESCRIPT
interface Config {
host?: string;
port?: number;
debug?: boolean;
}
// Required Make all fields required——Suitable for verifying logic
type RequiredConfig = Required<Config>;
// { host: string; port: number; debug: boolean }
function validateConfig(config: RequiredConfig): void {
console.log(`${config.host}:${config.port} (debug: ${config.debug})`);
}
(3) Somente leitura — Todas as propriedades passam a ser somente leitura
TYPESCRIPT
interface Point {
x: number;
y: number;
}
// Readonly Make all properties read-only
type ReadonlyPoint = Readonly<Point>;
// { readonly x: number; readonly y: number }
let point: ReadonlyPoint = { x: 1, y: 2 };
// point.x = 10; // ❌ Read-only properties cannot be modified.
// Common Uses:Function Parameter Protection
function freezeConfig(config: Readonly<Config>): void {
// config.host = "other"; // ❌ Modifications are not allowed.
console.log("Configuration Frozen");
}
▶ Exemplo: Conversão de tipos em CRUD
TYPESCRIPT
interface Article {
id: number;
title: string;
content: string;
author: string;
createdAt: Date;
updatedAt: Date;
}
// At the time of creation:Not necessary id and timestamps
type CreateArticle = Omit<Article, "id" | "createdAt" | "updatedAt">;
// When updating:All fields are optional
type UpdateArticle = Partial<Omit<Article, "id" | "createdAt">>;
// List View:Show only some fields
type ArticleSummary = Pick<Article, "id" | "title" | "author" | "createdAt">;
// Create
let newArticle: CreateArticle = {
title: "TypeScriptGetting Started",
content: "TypeScript is a superset of JavaScript...",
author: "Charlie"
};
// Update
let updateData: UpdateArticle = {
title: "TypeScript Advanced",
content: "An In-Depth Understanding of Generics..."
};
// List
let summary: ArticleSummary = {
id: 1,
title: "TypeScriptGetting Started",
author: "Charlie",
createdAt: new Date()
};
console.log("Create:" + newArticle.title);
console.log("Update:" + (updateData.title ?? "No changes"));
console.log("Abstract:" + summary.title);
Saída:
TEXT
Create:TypeScriptGetting Started
Update:TypeScript Advanced
Abstract:TypeScriptGetting Started
2. Aula sobre seleção de atributos
(1) Escolha — Selecione determinados atributos
TYPESCRIPT
interface User {
id: number;
name: string;
email: string;
password: string;
role: string;
}
// Pick Select the specified property
type UserPublic = Pick<User, "id" | "name" | "email">;
// { id: number; name: string; email: string }
let publicProfile: UserPublic = {
id: 1,
name: "Charlie",
email: "xiao@example.com"
};
// None password and role —— Safely Disclosing Public Information
(2) Omitir — Excluir determinados atributos
TYPESCRIPT
// Omit Exclude the specified properties(Pick the opposite of)
type UserSafe = Omit<User, "password">;
// { id: number; name: string; email: string; role: string }
let safeUser: UserSafe = {
id: 1,
name: "Charlie",
email: "xiao@example.com",
role: "admin"
};
// password Excluded
(3) Escolher ou omitir: a escolha
TYPESCRIPT
// Retain a few properties → Pick More concise
type Mini = Pick<User, "id" | "name">; // 2a property → Pick
// Exclude a few attributes → Omit More concise
type NoPassword = Omit<User, "password">; // Exclusion1 → Omit
// Preserve Most Properties → Omit More concise
type AlmostAll = Omit<User, "password">; // Retain4 → Omit
// Exclude Most Attributes → Pick More concise
type OnlyTwo = Pick<User, "id" | "name">; // Exclusion3 → Pick
3. Classes de operação do tipo união
(1) Excluir — Excluir do tipo de união
TYPESCRIPT
type AllTypes = "a" | "b" | "c" | "d";
// Exclude Exclude Specified Members
type WithoutA = Exclude<AllTypes, "a">; // "b" | "c" | "d"
type WithoutAB = Exclude<AllTypes, "a" | "b">; // "c" | "d"
(2) Extração — Extração de um tipo de união
TYPESCRIPT
type Mixed = string | number | boolean | null;
// Extract Extract Specified Members
type OnlyString = Extract<Mixed, string>; // string
type StringOrNumber = Extract<Mixed, string | number>; // string | number
(3) NonNullable — Excluir valores nulos e indefinidos
TYPESCRIPT
type MaybeString = string | null | undefined;
// NonNullable Exclusion null and undefined
type DefiniteString = NonNullable<MaybeString>; // string
▶ Exemplo: Filtragem de valores inválidos
TYPESCRIPT
type EventName = "click" | "focus" | "blur" | null | undefined;
// Exclusion null and undefined
type ValidEvent = NonNullable<EventName>; // "click" | "focus" | "blur"
// Keep only mouse events
type MouseEvent = Extract<ValidEvent, "click">; // "click"
// Exclusion click Unforeseen events
type NonClick = Exclude<ValidEvent, "click">; // "focus" | "blur"
function handleEvent(event: ValidEvent): void {
console.log(`Handling Events:${event}`);
}
handleEvent("click"); // ✅
handleEvent("focus"); // ✅
// handleEvent(null); // ❌ NonNullable Ruled out
Saída:
TEXT
// Executed successfully
4. Classes de operação do tipo função
(1) ReturnType — Obter o tipo de retorno da função
TYPESCRIPT
function createUser(name: string, age: number) {
return { name, age, active: true };
}
// ReturnType Get the return type——No handwriting required
type User = ReturnType<typeof createUser>;
// { name: string; age: number; active: boolean }
let user: User = { name: "Diana", age: 22, active: false };
(2) Parâmetros — Recuperar uma tupla com os tipos dos parâmetros da função
TYPESCRIPT
function register(name: string, email: string, age: number): void {}
// Parameters Get Parameter Type
type RegisterParams = Parameters<typeof register>;
// [string, string, number]
let params: RegisterParams = ["Charlie", "xiao@example.com", 20];
(3) ConstructorParameters — Obter os tipos dos parâmetros do construtor
TYPESCRIPT
class Point {
constructor(public x: number, public y: number, public z?: number) {}
}
type PointParams = ConstructorParameters<typeof Point>;
// [number, number, number?]
let args: PointParams = [1, 2];
let point = new Point(...args);
(4) InstanceType — Obter o tipo da instância do construtor
TYPESCRIPT
class Session {
constructor(public token: string) {}
isValid(): boolean { return this.token.length > 0; }
}
type SessionInstance = InstanceType<typeof Session>;
// Equivalent to Session Type
let session: SessionInstance = new Session("abc123");
5. Record — Criando um tipo de par chave-valor
Record é um dos tipos de dados mais utilizados — um tipo que permite criar rapidamente mapeamentos do tipo “chave-valor”:
TYPESCRIPT
// Basic Usage:Key and Value Types
type StringMap = Record<string, string>;
let translations: StringMap = {
hello: "Hello",
goodbye: "Goodbye"
};
// Coordinated Literal-Union Types——Precision Control Key
type Theme = "light" | "dark";
type ThemeColors = Record<Theme, { bg: string; text: string }>;
let themes: ThemeColors = {
light: { bg: "#ffffff", text: "#333333" },
dark: { bg: "#1a1a1a", text: "#e0e0e0" }
};
// Abbreviation: Use Record instead of handwritten Object Types
type Scores = Record<"Chinese Language" | "Mathematics" | "English", number>;
let myScores: Scores = { Chinese Language: 90, Mathematics: 95, English: 88 };
6. Como funcionam os tipos de ferramentas
Compreender a implementação subjacente dos tipos de ferramentas ajuda a personalizá-los:
(1) Implementação de Partial
TYPESCRIPT
type Partial<T> = {
[K in keyof T]?: T[K];
};
keyof T—— O tipo de união de todas as chaves de propriedade de T[K in keyof T]— Percorrer cada chave de propriedade (tipo mapeado)?— Adicionar um modificador opcionalT[K]— Mantém o tipo original do valor do atributo
(2) Implementação do Readonly
TYPESCRIPT
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
(3) Implementação do Pick
TYPESCRIPT
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
(4) Implementação do Omit
TYPESCRIPT
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
(5) Implementação do Record
TYPESCRIPT
type Record<K extends keyof any, T> = {
[P in K]: T;
};
▶ Exemplo: Tipos de ferramentas personalizadas
TYPESCRIPT
// DeepPartial——Recursion makes all levels optional
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
interface Config {
server: {
host: string;
port: number;
};
database: {
url: string;
pool: {
min: number;
max: number;
};
};
}
type PartialConfig = DeepPartial<Config>;
// Properties at all levels are now optional
let config: PartialConfig = {
server: { host: "localhost" } // port Can be omitted
// database The entire section can be omitted.
};
// DeepReadonly——Recursively set all levels to read-only
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
type FrozenConfig = DeepReadonly<Config>;
// config.server.host = "other"; // ❌ Deep Read-Only
Saída:
TEXT
// Executed successfully
❓ Perguntas Frequentes
P Qual é a diferença entre
Partial e propriedades opcionais?R As propriedades opcionais são marcadas manualmente com
? when defining an interface. Partial is a tool type—it automatically makes all properties of an existing type optional. The difference is that Partial is "derived from an existing type" and does not require redefining the interface. In actual development, the UpdateUser = Partial<User>. A operação de atualização é o caso de uso mais comum.P Devo usar
Pick ou Omit?R Depende do que for mais conciso — use
Pick quando houver menos propriedades a serem mantidas e use Omit quando houver menos propriedades a serem excluídas. Os dois são complementares; escolha o mais curto. A legibilidade do código é fundamental — Omit<User, "password"> é muito mais claro do que Pick<User, "id" | "name" | "email" | "role">.P O
ReturnType consegue determinar o tipo de retorno de uma função assíncrona?R As funções assíncronas retornam uma Promise; o
ReturnType<typeof asyncFn> retorna Promise<T> em vez de T. É preciso desembrulhar a Promise usando Awaited<ReturnType<typeof asyncFn>> (o TypeScript 4.5+ inclui o tipo Awaited).P O tipo de ferramenta afeta o desempenho?
R Não. O tipo de ferramenta é puramente uma construção em tempo de compilação — todas as informações de tipo são apagadas após a compilação, resultando em sobrecarga zero em tempo de execução. No entanto, um aninhamento excessivamente complexo de tipos pode aumentar o tempo de compilação, embora o impacto real seja insignificante.
📖 Resumo
- Parcial/Obrigatório/Somente leitura: a natureza opcional e de somente leitura dos atributos de transformação
- Selecionar/Omitir: selecione ou exclua um atributo específico — opte pela opção mais concisa
- Record: Crie rapidamente tipos de pares chave-valor e controle com precisão as chaves em conjunto com tipos de união literais
- Operações de exclusão/extração/não nulas em membros de tipos compostos
- ReturnType/Parameters/ConstructorParameters: Extraia informações de tipo sobre uma função
- Os tipos de ferramentas se baseiam nos tipos de mapas +
keyof— depois de entender como funcionam, você poderá criar seus próprios tipos de ferramentas
📝 Exercícios
- Exercício básico (Dificuldade ⭐): Defina a interface
Todo(id, título, concluído, criadoEm), e depois use o tipo de ferramenta para criar:CreateTodo(id e hora não são obrigatórios na criação),UpdateTodo(todos os campos são opcionais na atualização) eTodoPreview(exibe apenas título e concluído). - Exercício avançado (Dificuldade ⭐⭐): Personalize o tipo de ferramenta
Mutable<T>— remova todos os modificadoresreadonly(usando o mapeamento de modificadores-readonly). Em seguida, useReadonly<Config>para criar uma configuração somente leitura e useMutable<Readonly<Config>>para verificar se a capacidade de gravação foi restaurada. - Desafio (Dificuldade: ⭐⭐⭐): Implemente o tipo de ferramenta
PathKeys<T>— extraia recursivamente todos os caminhos das propriedades de objetos aninhados. Por exemplo,{ user: { name: string; address: { city: string } } }→"user" | "user.name" | "user.address" | "user.address.city".