Ao transformar arrays com map, é comum precisar apenas de propriedades específicas em vez do objeto inteiro. Escrever isso inline pode ser verboso, mas definir uma função de extração de propriedades antecipadamente permite expressões concisas como map(propsExtractor('id', 'name')).
Código
type LiteralObject = Record<string, unknown>
/** * Gera uma função que extrai apenas propriedades especificadas de um objeto */export function propsExtractor< Props extends LiteralObject, PropKey extends keyof Props,>( ...props: PropKey[]): (obj: Props) => Pick<Props, PropKey> { return (obj: Props) => { const result: Partial<Props> = {} for (const prop of props) { if (Object.hasOwn(obj, prop)) { result[prop] = obj[prop] } } return result as Pick<Props, PropKey> }}Uso
type User = { id: string name: string email: string role: string createdAt: Date}
const users: User[] = [ { id: '1', name: 'Alice', email: 'alice@example.com', role: 'admin', createdAt: new Date() }, { id: '2', name: 'Bob', email: 'bob@example.com', role: 'user', createdAt: new Date() },]
// Extrair apenas ID e nomeconst userSummaries = users.map(propsExtractor('id', 'name'))// => [{ id: '1', name: 'Alice' }, { id: '2', name: 'Bob' }]
// Funciona bem mesmo em maps aninhadosconst departments = [ { name: 'Engineering', members: users }, { name: 'Sales', members: users },]
const summaries = departments.map(dept => ({ department: dept.name, members: dept.members.map(propsExtractor('id', 'name'))}))Como Funciona
propsExtractoraceita nomes de propriedades para extrair como argumentos variádicos- Retorna uma função do tipo
(obj: Props) => Pick<Props, PropKey>como closure - A função retornada verifica a existência da propriedade com
Object.hasOwnantes de extrair - O tipo utilitário
Pickdo TypeScript garante inferência de tipo precisa para o valor de retorno
Usar Object.hasOwn garante segurança ao não extrair erroneamente propriedades da cadeia de protótipos.
Benefícios
- Legível: A intenção é clara com expressões como
map(propsExtractor('id', 'name')) - Type-safe: A inferência de tipo do TypeScript determina com precisão o tipo extraído
- Reutilizável: Defina uma vez, use em vários locais
- Lida bem com aninhamento: Mantém a legibilidade mesmo com múltiplas aplicações de
mapBy
Cuidados
Propriedades que não existem não são incluídas no resultado (nem mesmo como undefined). Se você quiser incluir todas as propriedades, remova a verificação Object.hasOwn. Além disso, se estiver extraindo muitas propriedades, definir explicitamente uma interface pode ser mais sustentável.
Aplicações
- Extrair apenas campos necessários de respostas de API antes de retornar aos clientes
- Excluir propriedades contendo informações sensíveis durante o logging (criar uma versão de filtro inverso)
- Extrair estado parcial em seletores Redux ou Zustand
- Implementar lógica de recuperação parcial semelhante à seleção de campos GraphQL
hsb.horse