Concepto 4 de 12
Tipos mapeados
Un tipo mapeado es un bucle sobre una unión de claves que construye un objeto. Partial, Required, Readonly y Pick son una línea de esto cada uno, y cuando la forma te resulte familiar podrás escribir cualquiera de memoria.
- Expresión
Flags<"read"> - Se resuelve a
{ read: boolean } - Expresión
Flags<"read" | "write"> - Se resuelve a
{ read: boolean; write: boolean }
Cada miembro de la unión de claves se convierte en una propiedad. La regla del valor se aplica a cada clave.
Definición del tipo
type Flags<K extends string> = { [P in K]: boolean }La forma
type MyPartial<T> = { [K in keyof T]?: T[K] } // ^^^^^^^^^^^^^^ ^ ^^^^ // key set | value type // modifier
Léelo así: para cada K de este conjunto de claves, produce una propiedad llamada K cuyo tipo es esa expresión. El conjunto de claves es cualquier unión de string, number o symbol — normalmente keyof T, a veces un parámetro, ocasionalmente algo calculado.
Los modificadores suman y restan
type Optional<T> = { [K in keyof T]+?: T[K] } // add ? type Required<T> = { [K in keyof T]-?: T[K] } // remove ? type Frozen<T> = { readonly [K in keyof T]: T[K] } type Thawed<T> = { -readonly [K in keyof T]: T[K] }
Mapear sobre un keyof T desnudo es *homomórfico*, lo que significa que los modificadores ? y readonly existentes se copian automáticamente. Por eso un mapeo identidad no cambia nada, y por eso quitar un modificador exige un menos explícito.
Renombrar claves con as
type Getters<T> = { [K in keyof T as `get${Capitalize<K & string>}`]: () => T[K] } // A key renamed to never disappears — this is how you filter. type OnlyStrings<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] }
La cláusula as reescribe cada clave mientras corre el mapeo. Una clave reescrita a never no puede existir, así que la propiedad se elimina — y es la única forma de quitar una propiedad de un tipo objeto.
El error más común
// Intent: keep only the string-valued properties. type OnlyStrings<T> = { [K in keyof T]: T[K] extends string ? T[K] : never } // Every key survives; the rejected ones just hold never. // { name: string; age: never }
Filtrar del lado del valor no puede eliminar una clave, solo vaciarla. El filtrado ocurre en la cláusula de clave con as ... : never, y confundir ambos produce un tipo que parece filtrado y no impone nada.
Ejercicio
Haz que cada propiedad de T sea string, conservando las mismas claves.
Pruébalo
1type User = { id: number; admin: boolean }Stringify<User>—→ { id: string; admin: string }
Para recordar
{ [K in Claves]: Valor } es el bucle. Los modificadores se aplican a la propiedad, as reescribe la clave, y never como clave es cómo desaparecen las cosas.
Se practica en
- #212Reconstruye PickPar 2
- #219Reconstruye PartialPar 2
- #226Reconstruye ReadonlyPar 2
- #235EligePorTipoPar 3
- #236GettersPar 3
- #241Reconstruye RequiredPar 2
- #242FusionaPar 3
- #246EntradasPar 4
- #247Omitir por tipoPar 3
- #249Opcionales, pero solo estasPar 3
- #256InvertirPar 3
- #257De tupla a objetoPar 3
- #258Qué claves son opcionalesPar 4
- #263Desde entradasPar 3
- #270Todos los valores del objetoPar 3
- #274Reemplaza claves de una uniónPar 4
- #278Claves en camelCasePar 3

