Skip to content
Require exactly one property

    ↑↓ move · ⏎ open · esc close

    Patterns

    How do I accept one search key while rejecting both an empty query and a query with several keys?

    Build one variant per key: require that key and forbid every other key with optional `never`.

    The recipe

    type ExactlyOne<T> = {
      [K in keyof T]:
        Required<Pick<T, K>> &
        Partial<Record<Exclude<keyof T, K>, never>>
    }[keyof T]
    
    type Search = ExactlyOne<{
      id: string
      email: string
      handle: string
    }>

    The build compiles this and checks each result below.

    How it works

    1. 01
      Required<Pick<T, K>>

      The current variant requires its selected key.

    2. 02
      Partial<Record<Exclude<keyof T, K>, never>>

      Every unselected key is optional but forbidden when present.

    What you get

    Where it goes wrong

    Like `AtLeastOne`, this creates one union member per key. Keep the source object small or the resulting diagnostics and editor work will grow quickly.

    Takeaway

    Require the selected key, forbid the rest, then index the mapped table to form the union.

    See also

    Patterns