Skip to main content

no-redundant-type-constituents

Disallow members of unions and intersections that do nothing or override type information.

💭

This rule requires type information to run, which comes with performance tradeoffs.

Some types can override some other types ("constituents") in a union or intersection and/or be overridden by some other types. TypeScript's set theory of types includes cases where a constituent type might be useless in the parent union or intersection.

Within | unions:

  • any and unknown "override" all other union members
  • never is dropped from unions in any position except when in a return type position
  • primitive types such as string "override" any of their literal types such as ""

Within & intersections:

  • any and never "override" all other intersection members
  • unknown is dropped from intersections
  • literal types "override" any primitive types in an intersection
  • literal types such as "" "override" any of their primitive types such as string
eslint.config.mjs
export default defineConfig({
rules: {
"@typescript-eslint/no-redundant-type-constituents": "error"
}
});

Try this rule in the playground ↗

Examples​

type UnionAny = any | 'foo';
type UnionUnknown = unknown | 'foo';
type UnionNever = never | 'foo';

type UnionBooleanLiteral = boolean | false;
type UnionNumberLiteral = number | 1;
type UnionStringLiteral = string | 'foo';

type IntersectionAny = any & 'foo';
type IntersectionUnknown = string & unknown;
type IntersectionNever = string | never;

type IntersectionBooleanLiteral = boolean & false;
type IntersectionNumberLiteral = number & 1;
type IntersectionStringLiteral = string & 'foo';
Open in Playground

Limitations​

This rule plays it safe and only works with bottom types, top types, and comparing literal types to primitive types.

Options​

This rule is not configurable.

When Not To Use It​

Some projects choose to occasionally intentionally include a redundant type constituent for documentation purposes. For example, the following code includes string in a union even though the unknown makes it redundant:

/**
* Normally a string name, but sometimes arbitrary unknown data.
*/
type NameOrOther = string | unknown;

If you strongly feel a preference for these unnecessary type constituents, this rule might not be for you.

Further Reading​


Type checked lint rules are more powerful than traditional lint rules, but also require configuring type checked linting.

See Troubleshooting > Linting with Type Information > Performance if you experience performance degradations after enabling type checked rules.

Resources​