oxc-project/oxc · warning · OxcDiagnostic

An index signature is preferred over a record.

Error message

An index signature is preferred over a record.

What it means

Warning from typescript/consistent-indexed-object-style (crates/oxc_linter/src/rules/typescript/consistent_indexed_object_style.rs:36). With the option 'index-signature', keyed types must use index-signature syntax; it fires on Record<K, V> usages and tells you to write '{ [key: string]: unknown }' instead.

Source

Thrown at crates/oxc_linter/src/rules/typescript/consistent_indexed_object_style.rs:36

    rule::{DefaultRuleConfig, Rule},
};

fn consistent_indexed_object_style_diagnostic(
    preferred: ConsistentIndexedObjectStyleConfig,
    span: Span,
) -> OxcDiagnostic {
    let (warning_message, help_message) = match preferred {
        ConsistentIndexedObjectStyleConfig::Record => (
            "A record is preferred over an index signature.",
            "Use a record type such as `Record<string, unknown>` instead of an index signature.",
        ),
        ConsistentIndexedObjectStyleConfig::IndexSignature => (
            "An index signature is preferred over a record.",
            "Use an index signature such as `{ [key: string]: unknown }` instead of a record type.",
        ),
    };

    OxcDiagnostic::warn(warning_message).with_help(help_message).with_label(span)
}

#[derive(Debug, Clone, Default, Deserialize)]
pub struct ConsistentIndexedObjectStyle(ConsistentIndexedObjectStyleConfig);

#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Deserialize, Serialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
enum ConsistentIndexedObjectStyleConfig {
    /// When set to `record`, enforces the use of a `Record` for indexed object types, e.g. `Record<string, unknown>`.
    #[default]
    Record,
    /// When set to `index-signature`, enforces the use of indexed signature types, e.g. `{ [key: string]: unknown }`.
    IndexSignature,
}

declare_oxc_lint!(
    /// ### What it does
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Rewrite Record<K, V> as '{ [key: K]: V }' (e.g. '{ [key: string]: unknown }')
  2. For Record with union keys like Record<'a'|'b', X>, map to explicit members or keep Record and disable per line with an explanation, since a plain index signature cannot express finite key unions
  3. If Record is the preferred house style, drop the custom option and use the default

Example fix

// before
type Dict = Record<string, unknown>;

// after
type Dict = { [key: string]: unknown };
Defensive patterns

Strategy: validation

Validate before calling

const RECORD = /:\s*Record\s*</;
for (const line of source.split('\n')) {
  if (RECORD.test(line)) fail('Record used; prefer an index signature (style: index-signature)', line);
}

Type guard

function isStringIndex(o: object): o is { [key: string]: unknown } {
  return Object.keys(o).every((k) => typeof k === 'string');
}

Prevention

When it happens

Trigger: oxlint runs with 'consistent-indexed-object-style': ['error', 'index-signature'] and the file contains 'type Dict = Record<string, unknown>', a parameter 'opts: Record<number, Foo>', or a nested Record inside another type.

Common situations: Codebases standardized on index signatures (often older or Angular-era conventions) enabling this non-default option; tooling that generates Record types being introduced into such a codebase; documentation examples using Record pasted into the project.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/3e339d34c85a815e. Report an issue: GitHub.