Skip to main content

prefer-type-fest-omit-index-signature

Require TypeFest OmitIndexSignature<T> over imported aliases like RemoveIndexSignature.

Targeted pattern scopeโ€‹

This rule targets imported alias names used for removing index signatures from object types.

What this rule reportsโ€‹

  • Type references that resolve to imported RemoveIndexSignature aliases.

Why this rule existsโ€‹

OmitIndexSignature is the canonical TypeFest utility for stripping index signatures while preserving explicitly-declared fields. Using the canonical name improves consistency across utility libraries.

โŒ Incorrectโ€‹

import type { RemoveIndexSignature } from "type-zoo";

type StrictUser = RemoveIndexSignature<User>;

โœ… Correctโ€‹

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

type StrictUser = OmitIndexSignature<User>;

Behavior and migration notesโ€‹

  • OmitIndexSignature<T> strips broad index signatures while preserving explicit properties.
  • This rule targets alias names with equivalent semantics (RemoveIndexSignature).
  • Use it when converting permissive dictionary-like types into explicit contract shapes.

Additional examplesโ€‹

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

import type { RemoveIndexSignature } from "type-zoo";

type Explicit = RemoveIndexSignature<User>;

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

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

type Explicit = OmitIndexSignature<User>;

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

type PublicModel = OmitIndexSignature<ModelWithIndex>;

ESLint flat config exampleโ€‹

import typefest from "eslint-plugin-typefest";

export default [
{
plugins: { typefest },
rules: {
"typefest/prefer-type-fest-omit-index-signature": "error",
},
},
];

When not to use itโ€‹

Disable this rule if external contract compatibility requires existing alias names.

Package documentationโ€‹

TypeFest package documentation:

Source file: source/omit-index-signature.d.ts

/**
* Omit any index signatures from the given object type, leaving only explicitly
* defined properties.
*
* This is the counterpart of `PickIndexSignature`.
*
* Use-cases:
*
* - Remove overly permissive signatures from third-party types.
*
* This type was taken from this [StackOverflow
* answer](https://stackoverflow.com/a/68261113/420747).
*
* It relies on the fact that an empty object (`{}`) is assignable to an object
* with just an index signature, like `Record<string, unknown>`, but not to an
* object with explicitly defined keys, like `Record<'foo' | 'bar', unknown>`.
*
* (The actual value type, `unknown`, is irrelevant and could be any type. Only
* the key type matters.)
*
* ```
* const indexed: Record<string, unknown> = {}; // Allowed
*
* // @ts-expect-error
* const keyed: Record<"foo", unknown> = {}; // Error
* // TS2739: Type '{}' is missing the following properties from type 'Record<"foo" | "bar", unknown>': foo, bar
* ```
*
* Instead of causing a type error like the above, you can also use a
* [conditional
* type](https://www.typescriptlang.org/docs/handbook/2/conditional-types.html)
* to test whether a type is assignable to another:
*
* ```
* type Indexed =
* {} extends Record<string, unknown>
* ? "โœ… `{}` is assignable to `Record<string, unknown>`"
* : "โŒ `{}` is NOT assignable to `Record<string, unknown>`";
*
* type IndexedResult = Indexed;
* //=> 'โœ… `{}` is assignable to `Record<string, unknown>`'
*
* type Keyed =
* {} extends Record<"foo" | "bar", unknown>
* ? "โœ… `{}` is assignable to `Record<'foo' | 'bar', unknown>`"
* : "โŒ `{}` is NOT assignable to `Record<'foo' | 'bar', unknown>`";
*
* type KeyedResult = Keyed;
* //=> 'โŒ `{}` is NOT assignable to `Record<\'foo\' | \'bar\', unknown>`'
* ```
*
* Using a [mapped
* type](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html#further-exploration),
* you can then check for each `KeyType` of `ObjectType`...
*
* ```
* type OmitIndexSignature<ObjectType> = {
* [KeyType in keyof ObjectType]: ObjectType[KeyType]; // Map each key of `ObjectType`... // ...to its original value, i.e. `OmitIndexSignature<Foo> == Foo`.
* };
* ```
*
* ...whether an empty object (`{}`) would be assignable to an object with that
* `KeyType` (`Record<KeyType, unknown>`)...
*
* ```
* type OmitIndexSignature<ObjectType> = {
* [
* KeyType in keyof ObjectType as {} extends Record<KeyType, unknown> // Is `{}` assignable to `Record<KeyType, unknown>`?
* ? never // โœ… `{}` is assignable to `Record<KeyType, unknown>`
* : KeyType
* ]: ObjectType[KeyType]; // โŒ `{}` is NOT assignable to `Record<KeyType, unknown>`
* };
* ```
*
* If `{}` is assignable, it means that `KeyType` is an index signature and we
* want to remove it. If it is not assignable, `KeyType` is a "real" key and we
* want to keep it.
*
* @category Object
*
* @example
* ```
* import type {OmitIndexSignature} from 'type-fest';
*
* type Example = {
* // These index signatures will be removed.
* [x: string]: any;
* [x: number]: any;
* [x: symbol]: any;
* [x: `head-${string}`]: string;
* [x: `${string}-tail`]: string;
* [x: `head-${string}-tail`]: string;
* [x: `${bigint}`]: string;
* [x: `embedded-${number}`]: string;
*
* // These explicitly defined keys will remain.
* foo: 'bar';
* qux?: 'baz';
* };
*
* type ExampleWithoutIndexSignatures = OmitIndexSignature<Example>;
* //=> {foo: 'bar'; qux?: 'baz'}
* ```
*
* @see {@link PickIndexSignature}
*/

Rule catalog ID: R051

Further readingโ€‹

Adoption resourcesโ€‹