Concepto 5 de 12
Modificadores
Los modificadores son la letra pequeña de los tipos mapeados. Son fáciles de escribir y fáciles de equivocar sutilmente, porque el comportamiento por defecto — copiar en silencio lo que ya había — se ve idéntico a no hacer nada.
- Expresión
Draft - Se resuelve a
{ readonly name?: string } - Expresión
Ready<Draft> - Se resuelve a
{ name: string }
Elimina readonly y la opcionalidad de cada propiedad. Aquí name pasa a ser obligatorio y modificable.
Definición del tipo
type Draft = { readonly name?: string }
type Ready<T> = { -readonly [K in keyof T]-?: T[K] }Los mapeos homomórficos heredan modificadores
interface Draft { title?: string; readonly id: number } // Mapping over bare `keyof T` preserves ? and readonly: type Copy<T> = { [K in keyof T]: T[K] } type Same = Copy<Draft> // { title?: string; readonly id: number } // Mapping over a computed key set does NOT: type Flat<T> = { [K in keyof T | never]: T[K] } type Bare = Flat<Draft> // { title: string; id: number }
Un mapeo es homomórfico solo cuando el conjunto de claves es exactamente keyof T para un parámetro T. Calcula el conjunto de otra forma — únelo, fíltralo, renómbralo con as — y todos los modificadores se pierden por defecto.
Esto pilla a la gente al escribir un tipo Merge: el resultado pierde la opcionalidad de ambas fuentes, y nada te avisa.
-? también quita undefined
type T = { a?: string } // a?: string | undefined type R = { [K in keyof T]-?: T[K] } // { a: string } — not { a: string | undefined }
Restar el modificador opcional hace dos cosas a la vez: la clave pasa a ser obligatoria y se elimina undefined del tipo del valor. Esa segunda parte es fácil de olvidar y suele ser justo lo que querías.
El error más común
// Intent: make everything optional. type Loose<T> = { [K in keyof T]: T[K] | undefined } // The key is still required — you must write { a: undefined } // rather than omitting it. Optional and "may be undefined" // are genuinely different properties.
Ensanchar el valor no es lo mismo que hacer la clave opcional, y las comprobaciones de igualdad exacta los distinguen. Si querías opcional, el ? va tras la cláusula de clave.
Ejercicio
Quita readonly de cada propiedad, y deja ? como está.
Pruébalo
1type Frozen = { readonly a: string; readonly b?: number }Thaw<Frozen>—→ { a: string; b?: number }
Para recordar
Los modificadores actúan sobre la propiedad, nunca sobre el valor. Y un mapeo que toque el conjunto de claves olvida todo modificador que no se le dijo que conservara.
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

