Saltar al contenido
webtype.orgwebtype.orgDoce conceptos · 5/12

    ↑↓ mover · ⏎ abrir · esc cerrar

    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.

    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

    1
    type 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