TypeScript: Tipos utilitários do TypeScript
Última atualização: 2026-08-26
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
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
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
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
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:
Create:TypeScriptGetting Started
Update:TypeScript Advanced
Abstract:TypeScriptGetting Started
2. Aula sobre seleção de atributos
(1) Escolha — Selecione determinados atributos
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
// 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
// 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
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
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
type MaybeString = string | null | undefined;
// NonNullable Exclusion null and undefined
type DefiniteString = NonNullable<MaybeString>; // string
▶ Exemplo: Filtragem de valores inválidos
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:
// Executed successfully
4. Classes de operação do tipo função
(1) ReturnType — Obter o tipo de retorno da função
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
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
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
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”:
// 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
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
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
(3) Implementação do Pick
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
(4) Implementação do Omit
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
(5) Implementação do Record
type Record<K extends keyof any, T> = {
[P in K]: T;
};
▶ Exemplo: Tipos de ferramentas personalizadas
// 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:
// Executed successfully
❓ Perguntas Frequentes
P: Qual é a diferença entre
Partiale propriedades opcionais? R: As propriedades opcionais são marcadas manualmente com?when defining an interface.Partialis a tool type—it automatically makes all properties of an existing type optional. The difference is thatPartialis "derived from an existing type" and does not require redefining the interface. In actual development, theUpdateUser = Partial<User>. A operação de atualização é o caso de uso mais comum.
P: Devo usar
PickouOmit? R: Depende do que for mais conciso — usePickquando houver menos propriedades a serem mantidas e useOmitquando 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 quePick<User, "id" | "name" | "email" | "role">.
P: O
ReturnTypeconsegue determinar o tipo de retorno de uma função assíncrona? R: As funções assíncronas retornam uma Promise; oReturnType<typeof asyncFn>retornaPromise<T>em vez deT. É preciso desembrulhar a Promise usandoAwaited<ReturnType<typeof asyncFn>>(o TypeScript 4.5+ inclui o tipoAwaited).
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".