Skip to content

Commit

Permalink
Merge branch 'main' into top-level-dependency-constraints-for-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bradzacher committed Oct 31, 2022
2 parents 3e85184 + 1f14c03 commit 7e0c2cc
Show file tree
Hide file tree
Showing 16 changed files with 836 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Expand Up @@ -308,7 +308,7 @@ module.exports = {
rules: {
// disallow ALL unused vars
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/sort-type-union-intersection-members': 'error',
'@typescript-eslint/sort-type-constituents': 'error',
},
},
{
Expand Down
6 changes: 6 additions & 0 deletions packages/eslint-plugin/docs/rules/consistent-type-imports.md
Expand Up @@ -48,6 +48,12 @@ type T = import('Foo').Foo;
const x: import('Bar') = 1;
```

## Usage with `emitDecoratorMetadata`

The `emitDecoratorMetadata` compiler option changes the code the TypeScript emits. In short - it causes TypeScript to create references to value imports when they are used in a type-only location. If you are using `emitDecoratorMetadata` then our tooling will require additional information in order for the rule to work correctly.

If you are using [type-aware linting](https://typescript-eslint.io/docs/linting/typed-linting), then you just need to ensure that the `tsconfig.json` you've configured for `parserOptions.project` has `emitDecoratorMetadata` turned on. Otherwise you can explicitly tell our tooling to analyze your code as if the compiler option was turned on [by setting `parserOptions.emitDecoratorMetadata` to `true`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/README.md#parseroptionsemitdecoratormetadata).

## When Not To Use It

- If you specifically want to use both import kinds for stylistic reasons, you can disable this rule.
101 changes: 101 additions & 0 deletions packages/eslint-plugin/docs/rules/sort-type-constituents.md
@@ -0,0 +1,101 @@
---
description: 'Enforce constituents of a type union/intersection to be sorted alphabetically.'
---

> 🛑 This file is source code, not the primary documentation location! 🛑
>
> See **https://typescript-eslint.io/rules/sort-type-constituents** for documentation.
Sorting union (`|`) and intersection (`&`) types can help:

- keep your codebase standardized
- find repeated types
- reduce diff churn

This rule reports on any types that aren't sorted alphabetically.

> Types are sorted case-insensitively and treating numbers like a human would, falling back to character code sorting in case of ties.
## Examples

<!--tabs-->

### ❌ Incorrect

```ts
type T1 = B | A;

type T2 = { b: string } & { a: string };

type T3 = [1, 2, 4] & [1, 2, 3];

type T4 =
| [1, 2, 4]
| [1, 2, 3]
| { b: string }
| { a: string }
| (() => void)
| (() => string)
| 'b'
| 'a'
| 'b'
| 'a'
| readonly string[]
| readonly number[]
| string[]
| number[]
| B
| A
| string
| any;
```

### ✅ Correct

```ts
type T1 = A | B;

type T2 = { a: string } & { b: string };

type T3 = [1, 2, 3] & [1, 2, 4];

type T4 =
| any
| string
| A
| B
| number[]
| string[]
| readonly number[]
| readonly string[]
| 'a'
| 'b'
| 'a'
| 'b'
| (() => string)
| (() => void)
| { a: string }
| { b: string }
| [1, 2, 3]
| [1, 2, 4];
```

## Options

### `groupOrder`

Each constituent of the type is placed into a group, and then the rule sorts alphabetically within each group.
The ordering of groups is determined by this option.

- `conditional` - Conditional types (`A extends B ? C : D`)
- `function` - Function and constructor types (`() => void`, `new () => type`)
- `import` - Import types (`import('path')`)
- `intersection` - Intersection types (`A & B`)
- `keyword` - Keyword types (`any`, `string`, etc)
- `literal` - Literal types (`1`, `'b'`, `true`, etc)
- `named` - Named types (`A`, `A['prop']`, `B[]`, `Array<C>`)
- `object` - Object types (`{ a: string }`, `{ [key: string]: number }`)
- `operator` - Operator types (`keyof A`, `typeof B`, `readonly C[]`)
- `tuple` - Tuple types (`[A, B, C]`)
- `union` - Union types (`A | B`)
- `nullish` - `null` and `undefined`
Expand Up @@ -6,6 +6,11 @@ description: 'Enforce members of a type union/intersection to be sorted alphabet
>
> See **https://typescript-eslint.io/rules/sort-type-union-intersection-members** for documentation.
:::danger Deprecated

This rule has been renamed to [`sort-type-union-intersection-members`](./sort-type-union-intersection-members.md).
:::

Sorting union (`|`) and intersection (`&`) types can help:

- keep your codebase standardized
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/configs/all.ts
Expand Up @@ -154,7 +154,7 @@ export = {
'@typescript-eslint/return-await': 'error',
semi: 'off',
'@typescript-eslint/semi': 'error',
'@typescript-eslint/sort-type-union-intersection-members': 'error',
'@typescript-eslint/sort-type-constituents': 'error',
'space-before-blocks': 'off',
'@typescript-eslint/space-before-blocks': 'error',
'space-before-function-paren': 'off',
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/index.ts
Expand Up @@ -115,6 +115,7 @@ import restrictPlusOperands from './restrict-plus-operands';
import restrictTemplateExpressions from './restrict-template-expressions';
import returnAwait from './return-await';
import semi from './semi';
import sortTypeConstituents from './sort-type-constituents';
import sortTypeUnionIntersectionMembers from './sort-type-union-intersection-members';
import spaceBeforeBlocks from './space-before-blocks';
import spaceBeforeFunctionParen from './space-before-function-paren';
Expand Down Expand Up @@ -245,6 +246,7 @@ export default {
'restrict-template-expressions': restrictTemplateExpressions,
'return-await': returnAwait,
semi: semi,
'sort-type-constituents': sortTypeConstituents,
'sort-type-union-intersection-members': sortTypeUnionIntersectionMembers,
'space-before-blocks': spaceBeforeBlocks,
'space-before-function-paren': spaceBeforeFunctionParen,
Expand Down
26 changes: 24 additions & 2 deletions packages/eslint-plugin/src/rules/no-extra-parens.ts
Expand Up @@ -141,8 +141,30 @@ export default util.createRule<Options, MessageIds>({
},
BinaryExpression: binaryExp,
CallExpression: callExp,
// ClassDeclaration
// ClassExpression
ClassDeclaration(node) {
if (node.superClass?.type === AST_NODE_TYPES.TSAsExpression) {
return rules.ClassDeclaration({
...node,
superClass: {
...node.superClass,
type: AST_NODE_TYPES.SequenceExpression as any,
},
});
}
return rules.ClassDeclaration(node);
},
ClassExpression(node) {
if (node.superClass?.type === AST_NODE_TYPES.TSAsExpression) {
return rules.ClassExpression({
...node,
superClass: {
...node.superClass,
type: AST_NODE_TYPES.SequenceExpression as any,
},
});
}
return rules.ClassExpression(node);
},
ConditionalExpression(node) {
// reduces the precedence of the node so the rule thinks it needs to be wrapped
if (util.isTypeAssertion(node.test)) {
Expand Down
23 changes: 17 additions & 6 deletions packages/eslint-plugin/src/rules/no-invalid-void-type.ts
Expand Up @@ -13,7 +13,8 @@ type MessageIds =
| 'invalidVoidNotReturnOrGeneric'
| 'invalidVoidNotReturn'
| 'invalidVoidNotReturnOrThisParam'
| 'invalidVoidNotReturnOrThisParamOrGeneric';
| 'invalidVoidNotReturnOrThisParamOrGeneric'
| 'invalidVoidUnionConstituent';

export default util.createRule<[Options], MessageIds>({
name: 'no-invalid-void-type',
Expand All @@ -25,14 +26,16 @@ export default util.createRule<[Options], MessageIds>({
},
messages: {
invalidVoidForGeneric:
'{{ generic }} may not have void as a type variable.',
'{{ generic }} may not have void as a type argument.',
invalidVoidNotReturnOrGeneric:
'void is only valid as a return type or generic type variable.',
'void is only valid as a return type or generic type argument.',
invalidVoidNotReturn: 'void is only valid as a return type.',
invalidVoidNotReturnOrThisParam:
'void is only valid as return type or type of `this` parameter.',
invalidVoidNotReturnOrThisParamOrGeneric:
'void is only valid as a return type or generic type variable or the type of a `this` parameter.',
'void is only valid as a return type or generic type argument or the type of a `this` parameter.',
invalidVoidUnionConstituent:
'void is not valid as a constituent in a union type',
},
schema: [
{
Expand Down Expand Up @@ -136,7 +139,7 @@ export default util.createRule<[Options], MessageIds>({
): void {
if (parentNode.default !== node) {
context.report({
messageId: 'invalidVoidNotReturnOrGeneric',
messageId: getNotReturnOrGenericMessageId(node),
node,
});
}
Expand Down Expand Up @@ -218,7 +221,7 @@ export default util.createRule<[Options], MessageIds>({
allowInGenericTypeArguments && allowAsThisParameter
? 'invalidVoidNotReturnOrThisParamOrGeneric'
: allowInGenericTypeArguments
? 'invalidVoidNotReturnOrGeneric'
? getNotReturnOrGenericMessageId(node)
: allowAsThisParameter
? 'invalidVoidNotReturnOrThisParam'
: 'invalidVoidNotReturn',
Expand All @@ -228,3 +231,11 @@ export default util.createRule<[Options], MessageIds>({
};
},
});

function getNotReturnOrGenericMessageId(
node: TSESTree.TSVoidKeyword,
): MessageIds {
return node.parent!.type === AST_NODE_TYPES.TSUnionType
? 'invalidVoidUnionConstituent'
: 'invalidVoidNotReturnOrGeneric';
}

0 comments on commit 7e0c2cc

Please sign in to comment.