TypeScript’s Record
O tipo simplifica o gerenciamento de estruturas de objetos com tipos de valor consistentes. Este guia abrange o essencial de Record
incluindo sua definição, sintaxe e como ela difere de outros tipos, como tuplas. Vamos aprender a definir e usar Record
Em cenários práticos, como aplicar o manuseio exaustivo de casos e o mapeamento de enumes. Além disso, exploraremos usos avançados combinando Record
com tipos de utilidade como Partial
Assim, Pick
e Readonly
.
Introdução
O Record
O tipo é um tipo de utilidade que nos permite criar um tipo de objeto com teclas especificadas e um tipo de valor uniforme. Esse tipo é particularmente útil para definir mapeamentos e garantir que todos os valores em um objeto estão em conformidade com um único tipo.
Definição do tipo de registro
A definição oficial do Documentação do TypeScript é:
Record<Keys, Type>
Aqui:
Keys
Representar o conjunto de chaves no registro, que pode ser uma união de literais de cordas ou um tipo derivado de uma união.Type
é o tipo de valores associados a essas teclas.
Por exemplo, Record
Define um objeto em que cada chave é uma string e todo valor é um número. Esse tipo garante que todas as propriedades do objeto tenham o mesmo tipo de valor, mas as teclas podem ser variadas.
Comparação entre um registro e uma tupla
Ambos Record
e Tuplas são usados para lidar com coleções de dados, mas servem a propósitos diferentes. Mesmo quando armazenam vários valores, eles diferem em estrutura e uso. Um registro nomeou propriedades com um tipo fixo, enquanto uma tupla é uma lista ordenada de elementos identificados por sua posição. Aqui está uma comparação simples:
- Registro. Cria um tipo de objeto em que todos os valores têm o mesmo tipo, mas as teclas podem ser flexíveis. Isso é útil para mapear as teclas para valores e garantir que todas as teclas sigam um tipo específico.
- Tupla. Define uma matriz com um número fixo de elementos, onde cada elemento pode ter um tipo diferente. As tuplas são usadas quando precisamos de uma coleção de tamanho fixo com tipos específicos para cada posição.
Por exemplo, considere o seguinte.
Aqui está um Record
Tipo, que mapeia as teclas da string para os valores do número:
type AgeMap = Record<string, number>;
Um tipo de tupla representa uma matriz com uma string (nome) e um número (idade) em uma posição fixa:
type Person = (string, number);
Uso básico do tipo de registro
O Record
O tipo fornece uma maneira simples e eficiente de mapear as teclas para os valores. É particularmente útil quando precisamos definir objetos com pares de chave -chave específicos, onde as teclas são de um tipo específico e os valores são de outro tipo.
Aqui estão algumas maneiras básicas de usar o Record
Digite para definir e criar dados estruturados.
Definindo um registro
Para definir um Record
especificamos os tipos para as chaves e valores. O exemplo abaixo define um objeto em que cada tecla é uma string e cada valor também é uma string. Isso pode ser usado para um mapa genérico de dados do usuário:
type User = Record<string, string>;
Criando um Record
Exemplo de tipo
Alguns sites têm vários subdomínios. Vamos supor que cada um desses subdomínios requer algum nível de acesso ao administrador e crie um Record
Digite para armazenar diferentes funções de administrador e seus níveis de acesso correspondentes. Aqui, UserRoles
e UserStatus
são Record
Tipos em que as chaves são literais específicos de cordas (admin
Assim, blogAdmin
Assim, docsAdmin
Assim, active
Assim, inactive
Assim, suspended
), e os valores são seqüências que descrevem cada função e status.
Primeiro, definimos um Record
tipo UserRoles
com funções de administrador específicas como chaves e suas descrições como valores. O UserRoles
Tipo garante que qualquer objeto desse tipo tenha chaves admin
Assim, blogAdmin
e docsAdmin
com valores de string descrevendo cada função. O roles
Objeto adere a esse tipo, fornecendo descrições para cada função de administrador:
type UserRoles = Record<'admin' | 'blogAdmin' | 'docsAdmin', string>;
const roles: UserRoles = {
admin: 'General Administrator with access to all areas.',
blogAdmin: 'Administrator with access to blog content.',
docsAdmin: 'Administrator with access to documentation.'
};
Em seguida, definimos um Record
tipo UserStatus
com status específicos como chaves e suas descrições como valores. O UserStatus
Tipo garante que qualquer objeto desse tipo tenha chaves active
Assim, inactive
e suspended
com valores de string descrevendo cada status. O userStatus
Objeto adere a esse tipo, fornecendo descrições para cada status:
type UserStatus = Record<'active' | 'inactive' | 'suspended', string>;
const userStatus: UserStatus = {
active: 'User is currently active and can use all features.',
inactive: 'User is currently inactive and cannot access their account.',
suspended: 'User account is suspended due to policy violations.'
};
Criando Record
Tipos dessa maneira, garantimos que as funções de administrador e os status do usuário sejam bem definidas e consistentes durante todo o aplicativo.
Casos de uso prático do tipo de registro
Nesta seção, revisaremos vários casos de uso prático do Record
Digite para demonstrar sua versatilidade e eficácia em diferentes cenários.
Usar Caso 1: Exibindo o manuseio de casos exaustivos
Usando Record
Definir um mapeamento entre valores e mensagens de caso nos permite lidar com cada caso possível explicitamente. Isso garante que todos os casos sejam cobertos e que quaisquer casos ausentes resultem em erros de tempo de compilação.
No exemplo abaixo, statusMessages
é a Record
onde as chaves são específicas Status
valores ('pending'
Assim, 'completed'
Assim, 'failed'
) e cada chave de chave para uma mensagem correspondente. O getStatusMessage
A função usa este registro para retornar a mensagem apropriada com base no status
parâmetro. Essa abordagem garante que todos os status sejam tratados de maneira correta e consistente.
Exemplo:
type Status = 'pending' | 'completed' | 'failed';
interface StatusInfo {
message: string;
severity: 'low' | 'medium' | 'high';
retryable: boolean;
}
const statusMessages: Record<Status, StatusInfo> = {
pending: {
message: 'Your request is pending.',
severity: 'medium',
retryable: true,
},
completed: {
message: 'Your request has been completed.',
severity: 'low',
retryable: false,
},
failed: {
message: 'Your request has failed.',
severity: 'high',
retryable: true,
},
};
function getStatusMessage(status: Status): string {
const info = statusMessages(status);
return `${info.message} Severity: ${info.severity}, Retryable: ${info.retryable}`;
}
console.log(getStatusMessage('completed'));
Caso de uso 2: Exibindo a verificação do tipo em aplicativos usando genéricos
Os genéricos no TypeScript permitem código flexível e reutilizável. Quando combinado com Record
os genéricos podem ajudar a aplicar a verificação do tipo e garantir que os objetos estejam em conformidade com estruturas específicas.
Usando genéricos com Record
podemos criar funções ou utilitários que geram objetos com um conjunto específico de chaves e um tipo de valor consistente. Essa abordagem aprimora a segurança e a reutilização do tipo em nossa base de código.
No exemplo abaixo, o createRecord
a função leva uma variedade de chaves e um valor, e retorna um Record
onde cada chave mapeia para o valor fornecido. Esta função usa genéricos (K
para chaves e T
para o tipo de valor) para garantir que o resultante Record
tem a estrutura correta.
Exemplo:
function createRecord<K extends string, T>(keys: K(), value: T): Record<K, T> {
const record: Partial<Record<K, T>> = {};
keys.forEach(key => record(key) = value);
return record as Record<K, T>;
}
interface RoleInfo {
description: string;
permissions: string();
}
const userRoles = createRecord(('admin', 'editor', 'viewer'), {
description: 'Default role',
permissions: ('read'),
});
console.log(userRoles);
Caso de uso 3: Mapeamento enums para dados
Usando Record
Mapear enums aos dados nos permite criar uma tabela de pesquisa onde cada valor de enumeração está associado a informações específicas. Isso é particularmente útil para cenários como definir configurações com base nos valores da enumeração.
Neste exemplo, colorHex
é a Record
isso mapeia cada um Color
Valor de enumeração ao seu código de cores hexadecimal correspondente. Essa abordagem fornece uma maneira clara e segura de tipo de lidar com dados relacionados a cores com base nos valores da enumeração.
Exemplo:
enum Color {
Red = 'RED',
Green = 'GREEN',
Blue = 'BLUE',
Yellow = 'YELLOW'
}
interface ColorInfo {
hex: string;
rgb: string;
complementary: string;
}
const colorHex: Record<Color, ColorInfo> = {
(Color.Red): {
hex: '#FF0000',
rgb: 'rgb(255, 0, 0)',
complementary: '#00FFFF',
},
(Color.Green): {
hex: '#00FF00',
rgb: 'rgb(0, 255, 0)',
complementary: '#FF00FF',
},
(Color.Blue): {
hex: '#0000FF',
rgb: 'rgb(0, 0, 255)',
complementary: '#FFFF00',
},
(Color.Yellow): {
hex: '#FFFF00',
rgb: 'rgb(255, 255, 0)',
complementary: '#0000FF',
},
};
console.log(colorHex(Color.Green));
Use Caso 4: Criando tabelas de pesquisa
Uma tabela de pesquisa usando Record
Ajuda no mapeamento de chaves (como identificadores, nomes) para valores específicos (como descrições, códigos). Isso pode ser útil para várias aplicações, incluindo configurações, traduções e muitas outras coisas.
Aqui, countryCode
é a Record
Isso mapeia os códigos do país para seus respectivos nomes de países, população, capitais e continentes. Esta tabela de pesquisa permite uma recuperação rápida e segura de tipo de nomes e populações de países com base em códigos de país.
Exemplo:
type CountryCode = "US" | "CA" | "MX" | "JP";
interface CountryInfo {
name: string;
population: number;
capital: string;
continent: string;
}
const countryLookup: Record<CountryCode, CountryInfo> = {
US: {
name: "United States",
population: 331000000,
capital: "Washington D.C.",
continent: "North America",
},
CA: {
name: "Canada",
population: 37700000,
capital: "Ottawa",
continent: "North America",
},
MX: {
name: "Mexico",
population: 128000000,
capital: "Mexico City",
continent: "North America",
},
JP: {
name: "Japan",
population: 126300000,
capital: "Tokyo",
continent: "Asia",
},
};
console.log(countryLookup.US);
console.log(countryLookup.US.population);
Iterando Record
Tipos
Iterando Record
Os tipos são importantes para acessar e manipular os dados nas estruturas de dados. Vamos criar dados de amostra e mostrar vários métodos sobre como podemos iterar sobre o datilograma Record
tipos.
Dados de amostra:
interface Course {
professor: string;
credits: number;
students: string();
}
interface Courses {
(key: string): Course;
}
const courses: Courses = {
Math101: {
professor: "Dr. Eze",
credits: 3,
students: ("Emmanuel", "Bob", "Charlie"),
},
History201: {
professor: "Dr. Jones",
credits: 4,
students: ("Dave", "Eve"),
},
};
Usando forEach
. Para usar forEach
com um Record
converta-o em uma variedade de pares de valor-chave:
Object.entries(courses).forEach(((key, value)) => {
console.log(`${key}: ${value.professor}, ${value.credits}`);
value.students.forEach(student => {
console.log(`Student: ${student}`);
});
});
Usando for...in
. O for...in
Loop itera sobre as chaves de um Record
:
for (const key in courses) {
if (courses.hasOwnProperty(key)) {
const course = courses(key);
console.log(`${key}: ${course.professor}, ${course.credits}`);
course.students.forEach(student => {
console.log(`Student: ${student}`);
});
}
}
Usando Object.keys()
. Object.keys()
retorna uma matriz do Record
Keys:
Object.keys(courses).forEach((key) => {
const course = courses(key);
console.log(`${key}: ${course.professor}, ${course.credits}`);
course.students.forEach(student => {
console.log(`Student: ${student}`);
});
});
Usando Object.values()
. Object.values()
retorna uma matriz do Record
valores:
Object.values(courses).forEach((course) => {
console.log(`${course.professor}, ${course.credits}`);
course.students.forEach(student => {
console.log(`Student: ${student}`);
});
});
Tipos avançados de uso e utilidade com Record
O Record
O tipo pode ser combinado com outros tipos de utilidade para obter maior flexibilidade e segurança do tipo. Esta seção expõe padrões de uso avançado, demonstrando como Record
pode trabalhar com tipos de serviços públicos como Pick
Assim, Readonly
e Partial
.
Combinando Record
com Pick
Para mapeamento de tipo seletivo
O Pick
O tipo de utilidade nos permite criar um novo tipo selecionando propriedades específicas de um tipo existente. Isso é útil quando queremos trabalhar com apenas um subconjunto de propriedades de um tipo maior.
Aqui, criamos um novo tipo SelectedProductInfo
escolhendo apenas o name
e price
propriedades do ProductInfo
interface, e depois usando Record
Para mapear produtos diferentes para este novo tipo:
interface ProductInfo {
name: string;
price: number;
category: string;
}
type SelectedProductInfo = Pick<ProductInfo, "name" | "price">;
type Product = 'Laptop' | 'Smartphone' | 'Tablet';
const products: Record<Product, SelectedProductInfo> = {
"Laptop": { name: "Dell XPS 15", price: 1500 },
"Smartphone": { name: "iPhone 12", price: 999 },
"Tablet": { name: "iPad Pro", price: 799 }
};
Combinando Record
com Readonly
Para propriedades imutáveis
O Readonly
O tipo de utilidade garante que as propriedades não possam ser modificadas depois que elas serem definidas. Isso é útil para criar estruturas de dados imutáveis.
O ReadonlyProductInfo
digite o exemplo abaixo faz todas as propriedades de ProductInfo
Imutível, garantindo que os detalhes de cada produto não possam ser alterados depois de definidos:
type ReadonlyProductInfo = Readonly<ProductInfo>;
const readonlyProducts: Record<Product, ReadonlyProductInfo> = {
"Laptop": { name: "Dell XPS 15", price: 1500, category: "Electronics" },
"Smartphone": { name: "iPhone 12", price: 999, category: "Electronics" },
"Tablet": { name: "iPad Pro", price: 799, category: "Electronics" }
};
Combinando Record
com Partial
Para propriedades opcionais
O Partial
O tipo de utilidade torna todas as propriedades de um tipo opcional. Isso é útil para cenários em que nem todas as propriedades podem ser conhecidas ou necessárias ao mesmo tempo.
Aqui, o PartialProductInfo
Tipo nos permite criar produtos com algumas ou nenhuma das propriedades definidas em ProductInfo
fornecendo flexibilidade na forma como as informações do produto são especificadas:
type PartialProductInfo = Partial<ProductInfo>;
const partialProducts: Record<Product, PartialProductInfo> = {
"Laptop": { name: "Dell XPS 15" },
"Smartphone": { price: 999 },
"Tablet": {}
};
Combinando Record
com Record
para mapeamento aninhado
Outro uso avançado envolve combinar Record
Tipos para criar mapeamentos aninhados, que podem ser particularmente úteis para gerenciar estruturas de dados complexas.
Neste exemplo, storeInventory
usa aninhado Record
tipos para mapear os departamentos para seus respectivos produtos e detalhes, demonstrando como Record
pode ser combinado para gerenciamento de dados mais complexo:
type Department = 'Electronics' | 'Furniture';
type ProductDetails = Record<Product, ProductInfo>;
const storeInventory: Record<Department, ProductDetails> = {
"Electronics": {
"Laptop": { name: "Dell XPS 15", price: 1500, category: "Electronics" },
"Smartphone": { name: "iPhone 12", price: 999, category: "Electronics" },
"Tablet": { name: "iPad Pro", price: 799, category: "Electronics" }
},
"Furniture": {
"Chair": { name: "Office Chair", price: 200, category: "Furniture" },
"Table": { name: "Dining Table", price: 500, category: "Furniture" },
"Sofa": { name: "Living Room Sofa", price: 800, category: "Furniture" }
}
};
Conclusão
O Record
O tipo é uma ferramenta versátil para gerenciar e estruturar os tipos de objetos, pois nos permite definir mapeamentos claros entre chaves e valores, garantindo a segurança e a consistência do tipo em nosso código.
Para obter informações mais detalhadas, consulte o Documentação do TypeScript e revisar outros recursos adicionais, como Typatript total e Tutorial de texto datilografado Para aprofundar sua compreensão do datilografado Record
Sistema de tipo.