oxc-project/oxc · warning · OxcDiagnostic

Always prefer `const x: T = { ... }`.

Error message

Always prefer `const x: T = { ... }`.

What it means

Warning from typescript/consistent-type-assertions via unexpected_object_type_assertion_diagnostic() (crates/oxc_linter/src/rules/typescript/consistent_type_assertions.rs:39). With objectLiteralTypeAssertions 'never' or 'allow-as-parameter', object literals must not be asserted; the rule demands 'const x: T = { ... }' (annotation) or 'satisfies', since asserting a literal skips exhaustiveness checking of its members.

Source

Thrown at crates/oxc_linter/src/rules/typescript/consistent_type_assertions.rs:39

fn use_angle_bracket_diagnostic(cast: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("Use `<{cast}>` instead of `as {cast}`."))
        .with_help(format!("Replace `as {cast}` with `<{cast}>`. For example, change `value as {cast}` to `<{cast}>value`."))
        .with_label(span)
}

fn use_as_diagnostic(cast: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!("Use `as {cast}` instead of `<{cast}>`.")).with_label(span)
}

fn never_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Do not use any type assertions.")
        .with_help("Remove the type assertion and use a type annotation instead. For example, change `const x = value as Type` to `const x: Type = value`. Alternatively, use the `satisfies` operator: `const x = value satisfies Type`.")
        .with_note("Type assertions bypass TypeScript's type checking and can hide type errors. Using type annotations or the `satisfies` operator provides better type safety while still allowing TypeScript to infer types where appropriate.")
        .with_label(span)
}

fn unexpected_object_type_assertion_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Always prefer `const x: T = { ... }`.")
        .with_help("Replace the object literal type assertion with a type annotation. For example, change `const x = { a: 1 } as Type` to `const x: Type = { a: 1 }`. Alternatively, use `const x = { a: 1 } satisfies Type` if you want TypeScript to infer the exact shape.")
        .with_note("Type assertions on object literals can hide errors where the object doesn't actually match the asserted type. Using type annotations or `satisfies` ensures TypeScript verifies that the object matches the expected type.")
        .with_label(span)
}

fn unexpected_array_type_assertion_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Always prefer `const x: T[] = [ ... ]`.")
        .with_help("Replace the array literal type assertion with a type annotation. For example, change `const x = [1, 2] as Type[]` to `const x: Type[] = [1, 2]`. Alternatively, use `const x = [1, 2] satisfies Type[]` if you want TypeScript to infer the exact array type.")
        .with_note("Type assertions on array literals can hide errors where the array doesn't actually match the asserted type. Using type annotations or `satisfies` ensures TypeScript verifies that the array matches the expected type.")
        .with_label(span)
}

#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, JsonSchema)]
#[serde(rename_all = "kebab-case")]
enum AssertionStyle {
    /// Enforce `as` syntax for type assertions.
    ///
    /// Examples of **incorrect** code with this option:

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Annotate the variable: 'const x: Type = { a: 1 };'
  2. Use 'const x = { a: 1 } satisfies Type;' to check compatibility while keeping the literal's inferred type
  3. If the literal is genuinely partial (filling defaults), model it as 'const x: Partial<Type> = {...}' then merge, or type the factory function's return
  4. Suppress rare intentional cases with an explained inline disable

Example fix

// before
const opts = { retries: 3 } as Options;

// after
const opts: Options = { retries: 3 };
Defensive patterns

Strategy: validation

Validate before calling

const OBJ_LITERAL_AS = /\{[\s\S]*?\}\s*as\s+\w+|<\w+>\s*\{/;
if (OBJ_LITERAL_AS.test(source)) fail('object literal asserted; annotate or use satisfies');

Type guard

function isShape<T extends object>(v: unknown, keys: (keyof T)[]): v is T {
  return typeof v === 'object' && v !== null && keys.every((k) => k in v);
}

Prevention

When it happens

Trigger: oxlint runs with objectLiteralTypeAssertions not set to 'allow' and the file contains 'const x = { a: 1 } as Type', 'foo({ b: 2 } as Options)', or '<Options>{ b: 2 }' — an assertion whose expression is an object literal (parenthesized parents count via outermost_paren_parent).

Common situations: Config objects initialized inline then cast to an options interface; default-parameter merges like '{ ...defaults, ...opts } as Config'; the cast hiding missing/renamed required properties after the target interface changes — exactly the class of bug the rule exists to catch.

Related errors


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