Skip to content
webtype.orgwebtype.org

    ↑↓ move · ⏎ open · esc close

    No. 241 · August 24, 2026 · Gentle

    Rebuild Required

    Implement MyRequired<T> so every optional property becomes required. This is the exact inverse of puzzle #219.

    01

    Try the puzzle yourself

    Par 2

    Puzzle

    rebuild-required.ts
    interface Draft {
      title?: string
      body?: string
    }
    Stroke 1 of 2Not run yet

    Replace ??? — your solution is checked against the cases below. Tab indents; press Escape then Tab to move focus out.

    Checks

    3
    • MyRequired<Draft>—
      → { title: string; body: string }
    • MyRequired<{ a?: number }>—
      → { a: number }
    • MyRequired<{ a: string }>—
      → { a: string }

    How a check is judged Exact type equality, not assignability — an intersection is not the same as the flattened object.

    How everyone did

    Fewer than 5 people have solved this one so far. The distribution appears once there is enough of a sample to mean anything.

    Short game

    Fewest characters

    No public scores yet.

    Archive
    02

    Annotated solution

    Published August 25, 2026

    The solution

    type MyRequired<T> = { [K in keyof T]-?: T[K] }

    The common wrong answer

    type MyRequired<T> = { [K in keyof T]: T[K] }

    This is the identity mapping, and that is the surprise: a mapped type over keyof T is *homomorphic*, so it copies the existing ? and readonly modifiers across rather than dropping them. Optional properties stay optional, and the type is unchanged.

    Line by line

    1. -?

      The minus subtracts the modifier. It does two things at once: the key stops being optional, and undefined is removed from the value type — which is why title?: string becomes title: string and not title: string | undefined.

    2. { [K in keyof T]

      Mapping directly over keyof T is what makes this homomorphic, and homomorphic is what makes modifiers inheritable in the first place. Map over a computed key set instead and every modifier is lost by default.

    Takeaway

    + and - before ? or readonly are the only way to change a property’s modifiers. Without them a mapped type quietly preserves whatever was already there, which makes "nothing happened" a very common bug.

    Uses