Skip to main content

prefer-type-fest-require-one-or-none

Require TypeFest RequireOneOrNone<T, Keys> over imported aliases like AtMostOne.

Targeted pattern scope​

This rule reports imported AtMostOne aliases and prefers RequireOneOrNone<T, Keys> for zero-or-one selector constraints.

Use this utility when a payload may omit all optional selectors, but must not provide two selectors at the same time.

What this rule reports​

  • Type references that resolve to imported AtMostOne aliases.

Detection boundaries​

  • βœ… Reports imported aliases with direct named imports.
  • ❌ Does not report namespace-qualified alias usage.
  • ❌ Does not auto-fix.

Why this rule exists​

RequireOneOrNone is the canonical TypeFest utility for expressing β€œzero or exactly one” optional key constraints. Canonical naming keeps type utility usage predictable in public codebases.

This pattern appears in query/filter payloads where no selector is valid but multiple selectors conflict.

❌ Incorrect​

import type { AtMostOne } from "type-aliases";

type OptionalAuth = AtMostOne<{
token?: string;
apiKey?: string;
}>;

βœ… Correct​

import type { RequireOneOrNone } from "type-fest";

type OptionalAuth = RequireOneOrNone<{
token?: string;
apiKey?: string;
}>;

Behavior and migration notes​

  • RequireOneOrNone<T, Keys> models selectors where zero is valid but more than one is invalid.
  • This rule targets alias names with equivalent semantics (AtMostOne).
  • Keep the key subset focused on mutually exclusive selectors to maintain readable contract intent.

Additional examples​

❌ Incorrect β€” Additional example​

import type { AtMostOne } from "custom-type-utils";

type MonitorLookup = AtMostOne<
{
monitorId?: string;
slug?: string;
},
"monitorId" | "slug"
>;

βœ… Correct β€” Additional example​

import type { RequireOneOrNone } from "type-fest";

type MonitorLookup = RequireOneOrNone<
{
monitorId?: string;
slug?: string;
},
"monitorId" | "slug"
>;

βœ… Correct β€” Repository-wide usage​

type SessionIdentity = RequireOneOrNone<
{ userId?: string; guestId?: string },
"userId" | "guestId"
>;

ESLint flat config example​

import typefest from "eslint-plugin-typefest";

export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-type-fest-require-one-or-none": "error",
},
},
];

When not to use it​

Disable this rule if existing alias names are part of a published API contract.

Package documentation​

TypeFest package documentation:

Source file: source/require-one-or-none.d.ts

/**
Create a type that requires exactly one of the given keys and disallows more, or none of the given keys. The remaining keys are kept as is.

@example
```
import type {RequireOneOrNone} from 'type-fest';

type Responder = RequireOneOrNone<{
text: () => string;
json: () => string;
secure: boolean;
}, 'text' | 'json'>;

const responder1: Responder = {
secure: true,
};

const responder2: Responder = {
text: () => '{"message": "hi"}',
secure: true,
};

const responder3: Responder = {
json: () => '{"message": "ok"}',
secure: true,
};
```

@category Object
*/

Rule catalog ID: R059

Further reading​

Adoption resources​