deslop/redundant-type-pattern

Disallow redundant type expressions with a no-op operand, e.g. `T & {}`, `Partial<Partial<T>>`, `Pick<X, keyof X>`.

  • Category: Architecture
  • Severity: warn
  • Source: deslop-js
  • Framework: global
  • Enabled when: react-doctor deadCode analysis enabled (default true); whole-project scan only — skipped in --diff/--staged modes
  • Documentation: https://github.com/millionco/deslop-js

Validation prompt

Use this to decide whether a fired diagnostic is real or a false positive.

Fires (always confidence "high", skipping .d.ts files) when deslop's detectRedundantTypePatterns finds a type expression whose operand is a no-op, tagged by kind: intersection-with-empty-object ("intersection with {} is a no-op; the empty object type does not constrain anything"), self-union ("union contains the same member twice") and self-intersection ("intersection contains the same operand twice") from a literally-equal duplicated member, nested-partial/nested-readonly/nested-required ("Partial<Partial<T>> collapses to Partial<T>", etc.), pick-all-keys ("Pick<X, keyof X> is equivalent to X itself"), omit-no-keys ("Omit<X, never> is equivalent to X itself"), or empty-interface-extends-one ("interface X extends Base with no new members"). False positive to SUPPRESS: an empty-interface-extends-one kept on purpose as a nominal branding marker or as a public declaration-merging / module-augmentation extension point that downstream code adds members to (the detector already excludes zod .infer and radix .Props aliases, so a remaining one is usually a deliberate seam); also leave T & {} if it is the intentional "force-simplify display" trick on a generic where you actually rely on the prettified hover type.

Fix prompt

Use this once validation confirms the diagnostic is real.

Apply deslop's per-kind suggestion, which is the simplification itself: for intersection-with-empty-object drop the & {} term (type A = B & {} becomes type A = B); for self-union/self-intersection delete the duplicated member (A | A becomes A); for nested-partial/readonly/required flatten the wrapper (Partial<Partial<T>> becomes Partial<T>); for pick-all-keys replace Pick<X, keyof X> with X and for omit-no-keys replace Omit<X, never> with X; for empty-interface-extends-one rewrite interface X extends Base {} as type X = Base unless you are intentionally keeping a branding or declaration-merging seam, in which case leave it and document the intent. These collapse to the identical type, so removing the no-op operand reduces noise without changing behavior. See https://www.typescriptlang.org/docs/handbook/utility-types.html