Skip to content
webtype.orgwebtype.org#258 optional-keys · par 4

    ↑↓ move · ⏎ open · esc close

    No. 258 · September 10, 2026 · Hard

    Which keys are optional

    Implement `OptionalKeys<T>` so it produces the union of the keys of `T` that are optional, and `never` when none of them are.

    01

    Try the puzzle yourself

    Par 4

    Puzzle

    optional-keys.ts
    Stroke 1 of 4Not run yet

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

    Checks

    3
    • OptionalKeys<{ a: string; b?: number }>
      'b'
    • OptionalKeys<{ a: string }>
      never
    • OptionalKeys<{ a?: 1; b?: 2 }>
      'a' | 'b'

    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 September 11, 2026

    The solution

    type OptionalKeys<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? K : never }[keyof T]

    The common wrong answer

    type OptionalKeys<T> = { [K in keyof T]: {} extends Pick<T, K> ? K : never }[keyof T]

    The detection is right and the answer still comes out wrong: `"b" | undefined` instead of `"b"`. Without `-?`, the mapping copies the optionality of each key onto its own result, so the very keys you are trying to collect are optional in your lookup table — and indexing an optional property adds `undefined` to what you get back.

    Line by line

    1. {} extends Pick<T, K>

      An object with one required property cannot accept `{}`; one with a single optional property can. That asymmetry is the whole test.

    2. -?

      Strip optionality from the table you are building. You are storing answers, not mirroring the input, and an answer that might be missing is not an answer.

    3. [keyof T]

      Indexing by every key at once collapses the table into a union, and the `never` entries vanish on their own — `never` in a union is nothing at all.

    Takeaway

    When a mapped type is a lookup table rather than a transformed copy, `-?` belongs on it. Inherited modifiers are for rebuilding an object; they only get in the way when you are computing an answer.

    Uses