Skip to main content

prefer-type-fest-require-at-least-one

Require TypeFest RequireAtLeastOne<T, Keys> over imported aliases like AtLeastOne.

Targeted pattern scopeโ€‹

This rule reports imported AtLeastOne aliases and prefers RequireAtLeastOne<T, Keys> for at-least-one field requirements.

It is especially valuable for search DTOs and patch/update payloads where empty objects should be rejected at compile time.

What this rule reportsโ€‹

  • Type references that resolve to imported AtLeastOne aliases.

Detection boundariesโ€‹

  • โœ… Reports imported aliases with direct named imports.
  • โŒ Does not report namespace-qualified aliases.
  • โŒ Does not auto-fix.

Why this rule existsโ€‹

RequireAtLeastOne is the canonical TypeFest utility for enforcing at least one required key among a set of optional candidates. Standardizing on canonical TypeFest naming keeps public type contracts easier to understand and maintain.

For user-facing APIs, this avoids accepting meaningless payloads like {} where at least one filter field is required.

โŒ Incorrectโ€‹

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

type Update = AtLeastOne<User>;

โœ… Correctโ€‹

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

type Update = RequireAtLeastOne<User>;

Behavior and migration notesโ€‹

  • RequireAtLeastOne<T, Keys> prevents empty-object payloads when at least one selector is required.
  • This rule targets alias names with equivalent semantics (AtLeastOne).
  • Use keyed variants for large object types to constrain only the fields that participate in the requirement.

Additional examplesโ€‹

โŒ Incorrect โ€” Additional exampleโ€‹

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

type UserSearch = AtLeastOne<
{
email?: string;
id?: string;
username?: string;
},
"email" | "id" | "username"
>;

โœ… Correct โ€” Additional exampleโ€‹

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

type UserSearch = RequireAtLeastOne<
{
email?: string;
id?: string;
username?: string;
},
"email" | "id" | "username"
>;

โœ… Correct โ€” Repository-wide usageโ€‹

type ProfilePatch = RequireAtLeastOne<
{ avatarUrl?: string; displayName?: string; bio?: string },
"avatarUrl" | "displayName" | "bio"
>;

ESLint flat config exampleโ€‹

import typefest from "eslint-plugin-typefest";

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

When not to use itโ€‹

Disable this rule if published contracts must preserve existing alias names.

Package documentationโ€‹

TypeFest package documentation:

Source file: source/require-at-least-one.d.ts

/**
Create a type that requires at least one of the given keys. The remaining keys are kept as is.

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

type Responder = {
text?: () => string;
json?: () => string;
secure?: boolean;
};

const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
json: () => '{"message": "ok"}',
secure: true,
};
```

@category Object
*/

Rule catalog ID: R057

Further readingโ€‹

Adoption resourcesโ€‹