TypeScript Meaningless Intersection

ID

javascript.ts_meaningless_intersection

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

JavaScript

Tags

reliability, types, typescript

Description

Reports a TypeScript intersection one of whose components is any, never or unknown, each of which decides the whole intersection on its own and makes the rest of it dead text.

Only the intersection operator is judged. A union with any is a related defect, spelled differently and with a different fix, and a bare any on its own belongs to javascript.ts_no_explicit_any. A component repeated inside an intersection is reported by javascript.ts_duplicate_union_component, which walks the same spine, and is deliberately not reported twice here.

Rationale

// Bad
type Loose = User & any;        // the result is any
type Impossible = User & never; // the result is never
type Opaque = unknown & User;   // the result is User

// Good
type Both = User & Admin;
  • any absorbs the intersection. The annotation looks like a narrowed User while every value passes and every member access is unchecked — the worst of the three, because it turns type checking off exactly where the author was trying to turn it up.

  • never empties it. No value can ever have the type, so every call site that tries to supply one fails, and the error names the argument rather than the declaration.

  • unknown vanishes from it. Harmless, and a sign of a merge or a refactor that left a placeholder behind.

  • All three arrive from an edit rather than from a decision: a generic parameter defaulted to any, a branch of a conditional type that resolved to never, a placeholder written while the real type was still being worked out.

Remediation

Drop the component that decides the type, or replace it with the constraint that was meant.

// Good — the intersection says what it constrains
type Privileged = User & Admin;

// Good — a generic parameter, constrained rather than widened
function merge<T extends object>(user: User & T): User & T {
  return user;
}

// Good — when the value really is unconstrained, say so once
function log(value: unknown): void {
  console.log(value);
}

© 2026 Xygeni. All rights reserved