Skip to content

Commit

Permalink
feat(eslint-plugin): add no-redundant-type-constituents rule (types…
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshuaKGoldberg committed Feb 27, 2022
1 parent 8743613 commit 0e4e151
Show file tree
Hide file tree
Showing 9 changed files with 1,376 additions and 2 deletions.
5 changes: 3 additions & 2 deletions .cspell.json
Expand Up @@ -71,8 +71,8 @@
"IIFE",
"IIFEs",
"linebreaks",
"markdownlint",
"lzstring",
"markdownlint",
"necroing",
"nocheck",
"nullish",
Expand Down Expand Up @@ -101,14 +101,15 @@
"transpiled",
"transpiles",
"transpiling",
"tsvfs",
"tsconfigs",
"tsutils",
"tsvfs",
"typedef",
"typedefs",
"unfixable",
"unoptimized",
"unprefixed",
"upsert",
"Zacher"
],
"overrides": [
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/README.md
Expand Up @@ -136,6 +136,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int
| [`@typescript-eslint/no-non-null-asserted-optional-chain`](./docs/rules/no-non-null-asserted-optional-chain.md) | Disallows using a non-null assertion after an optional chain expression | :white_check_mark: | | |
| [`@typescript-eslint/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) | Disallows non-null assertions using the `!` postfix operator | :white_check_mark: | | |
| [`@typescript-eslint/no-parameter-properties`](./docs/rules/no-parameter-properties.md) | Disallow the use of parameter properties in class constructors | | | |
| [`@typescript-eslint/no-redundant-type-constituents`](./docs/rules/no-redundant-type-constituents.md) | Disallow members of unions and intersections that do nothing or override type information | | | :thought_balloon: |
| [`@typescript-eslint/no-require-imports`](./docs/rules/no-require-imports.md) | Disallows invocation of `require()` | | | |
| [`@typescript-eslint/no-this-alias`](./docs/rules/no-this-alias.md) | Disallow aliasing `this` | :white_check_mark: | | |
| [`@typescript-eslint/no-type-alias`](./docs/rules/no-type-alias.md) | Disallow the use of type aliases | | | |
Expand Down
@@ -0,0 +1,85 @@
# `no-redundant-type-constituents`

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

## Rule Details

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`

Examples of code for this rule:

<!--tabs-->

### ❌ Incorrect

```ts
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';
```

### ✅ Correct

```ts
type UnionAny = any;
type UnionUnknown = unknown;
type UnionNever = never;

type UnionBooleanLiteral = boolean;
type UnionNumberLiteral = number;
type UnionStringLiteral = string;

type IntersectionAny = any;
type IntersectionUnknown = string;
type IntersectionNever = string;

type IntersectionBooleanLiteral = false;
type IntersectionNumberLiteral = 1;
type IntersectionStringLiteral = 'foo';

type ReturnUnionNever = () => string | never;
```

## Limitations

This rule plays it safe and only works with bottom types, top types, and comparing literal types to primitive types.
It also does not provide an auto-fixer just yet.

## Further Reading

- [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types)
- [Intersection Types](https://www.typescriptlang.org/docs/handbook/2/objects.html#intersection-types)
- [Bottom Types](https://en.wikipedia.org/wiki/Bottom_type)
- [Top Types](https://en.wikipedia.org/wiki/Top_type)

## Attributes

- [ ] ✅ Recommended
- [ ] 🔧 Fixable
- [x] 💭 Requires type information
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/configs/all.ts
Expand Up @@ -88,6 +88,7 @@ export = {
'@typescript-eslint/no-parameter-properties': 'error',
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',
'@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/no-require-imports': 'error',
'no-restricted-imports': 'off',
'@typescript-eslint/no-restricted-imports': 'error',
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/index.ts
Expand Up @@ -60,6 +60,7 @@ import noNonNullAssertedOptionalChain from './no-non-null-asserted-optional-chai
import noNonNullAssertion from './no-non-null-assertion';
import noParameterProperties from './no-parameter-properties';
import noRedeclare from './no-redeclare';
import noRedundantTypeConstituents from './no-redundant-type-constituents';
import noRequireImports from './no-require-imports';
import noRestrictedImports from './no-restricted-imports';
import noShadow from './no-shadow';
Expand Down Expand Up @@ -183,6 +184,7 @@ export default {
'no-non-null-assertion': noNonNullAssertion,
'no-parameter-properties': noParameterProperties,
'no-redeclare': noRedeclare,
'no-redundant-type-constituents': noRedundantTypeConstituents,
'no-require-imports': noRequireImports,
'no-restricted-imports': noRestrictedImports,
'no-shadow': noShadow,
Expand Down

0 comments on commit 0e4e151

Please sign in to comment.