From 720b624f36308f75bbcc2148e2ae6dcc35b8a6af Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sat, 20 Jul 2019 14:35:45 -0700 Subject: [PATCH 1/3] feat(eslint-plugin): add rule `consistent-type-assertions` Merges both `no-angle-bracket-type-assertion` and `no-object-literal-type-assertion` into one rule Fixes #332 Fixes #668 --- packages/eslint-plugin/README.md | 3 +- packages/eslint-plugin/ROADMAP.md | 11 +- .../docs/rules/consistent-type-assertions.md | 77 +++++ packages/eslint-plugin/src/configs/all.json | 3 +- packages/eslint-plugin/src/configs/base.json | 4 +- .../src/rules/consistent-type-assertions.ts | 158 +++++++++ packages/eslint-plugin/src/rules/index.ts | 2 + .../rules/no-angle-bracket-type-assertion.ts | 2 + .../rules/no-object-literal-type-assertion.ts | 2 + .../rules/consistent-type-assertions.test.ts | 302 ++++++++++++++++++ .../eslint-utils/batchedSingleLineTests.ts | 13 +- .../src/ts-estree/ts-estree.ts | 2 +- 12 files changed, 564 insertions(+), 15 deletions(-) create mode 100644 packages/eslint-plugin/docs/rules/consistent-type-assertions.md create mode 100644 packages/eslint-plugin/src/rules/consistent-type-assertions.ts create mode 100644 packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index ce069a2aff6..58418f7b9e4 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -130,6 +130,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e | [`@typescript-eslint/ban-types`](./docs/rules/ban-types.md) | Enforces that types will not to be used | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/camelcase`](./docs/rules/camelcase.md) | Enforce camelCase naming convention | :heavy_check_mark: | | | | [`@typescript-eslint/class-name-casing`](./docs/rules/class-name-casing.md) | Require PascalCased class and interface names | :heavy_check_mark: | | | +| [`@typescript-eslint/consistent-type-assertions`](./docs/rules/consistent-type-assertions.md) | Enforces consistent usage of type assertions. | :heavy_check_mark: | | | | [`@typescript-eslint/consistent-type-definitions`](./docs/rules/consistent-type-definitions.md) | Consistent with type definition either `interface` or `type` | | :wrench: | | | [`@typescript-eslint/explicit-function-return-type`](./docs/rules/explicit-function-return-type.md) | Require explicit return types on functions and class methods | :heavy_check_mark: | | | | [`@typescript-eslint/explicit-member-accessibility`](./docs/rules/explicit-member-accessibility.md) | Require explicit accessibility modifiers on class properties and methods | :heavy_check_mark: | | | @@ -140,7 +141,6 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e | [`@typescript-eslint/member-delimiter-style`](./docs/rules/member-delimiter-style.md) | Require a specific member delimiter style for interfaces and type literals | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/member-naming`](./docs/rules/member-naming.md) | Enforces naming conventions for class members by visibility | | | | | [`@typescript-eslint/member-ordering`](./docs/rules/member-ordering.md) | Require a consistent member declaration order | | | | -| [`@typescript-eslint/no-angle-bracket-type-assertion`](./docs/rules/no-angle-bracket-type-assertion.md) | Enforces the use of `as Type` assertions instead of `` assertions | :heavy_check_mark: | | | | [`@typescript-eslint/no-array-constructor`](./docs/rules/no-array-constructor.md) | Disallow generic `Array` constructors | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-empty-function`](./docs/rules/no-empty-function.md) | Disallow empty functions | | | | | [`@typescript-eslint/no-empty-interface`](./docs/rules/no-empty-interface.md) | Disallow the declaration of empty interfaces | :heavy_check_mark: | | | @@ -155,7 +155,6 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e | [`@typescript-eslint/no-misused-promises`](./docs/rules/no-misused-promises.md) | Avoid using promises in places not designed to handle them | | | :thought_balloon: | | [`@typescript-eslint/no-namespace`](./docs/rules/no-namespace.md) | Disallow the use of custom TypeScript modules and namespaces | :heavy_check_mark: | | | | [`@typescript-eslint/no-non-null-assertion`](./docs/rules/no-non-null-assertion.md) | Disallows non-null assertions using the `!` postfix operator | :heavy_check_mark: | | | -| [`@typescript-eslint/no-object-literal-type-assertion`](./docs/rules/no-object-literal-type-assertion.md) | Forbids an object literal to appear in a type assertion expression | :heavy_check_mark: | | | | [`@typescript-eslint/no-parameter-properties`](./docs/rules/no-parameter-properties.md) | Disallow the use of parameter properties in class constructors | :heavy_check_mark: | | | | [`@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` | | | | diff --git a/packages/eslint-plugin/ROADMAP.md b/packages/eslint-plugin/ROADMAP.md index 60cdbe7de24..4d1dc9e208b 100644 --- a/packages/eslint-plugin/ROADMAP.md +++ b/packages/eslint-plugin/ROADMAP.md @@ -70,7 +70,7 @@ | [`no-invalid-this`] | 🌟 | [`no-invalid-this`][no-invalid-this] | | [`no-misused-new`] | βœ… | [`@typescript-eslint/no-misused-new`] | | [`no-null-keyword`] | πŸ”Œ | [`no-null/no-null`] (doesn’t handle `null` type) | -| [`no-object-literal-type-assertion`] | βœ… | [`@typescript-eslint/no-object-literal-type-assertion`] | +| [`no-object-literal-type-assertion`] | βœ… | [`@typescript-eslint/consistent-type-assertions`] | | [`no-return-await`] | 🌟 | [`no-return-await`][no-return-await] | | [`no-shadowed-variable`] | 🌟 | [`no-shadow`][no-shadow] | | [`no-sparse-arrays`] | 🌟 | [`no-sparse-arrays`][no-sparse-arrays] | @@ -148,13 +148,13 @@ | [`import-spacing`] | πŸ”Œ | Use [Prettier] | | [`increment-decrement`] | 🌟 | [`no-plusplus`][no-plusplus] | | [`interface-name`] | βœ… | [`@typescript-eslint/interface-name-prefix`] | -| [`interface-over-type-literal`] | βœ… | [`@typescript-eslint/prefer-interface`] | +| [`interface-over-type-literal`] | βœ… | [`@typescript-eslint/consistent-type-definitions`] | | [`jsdoc-format`] | πŸŒ“ | [`valid-jsdoc`][valid-jsdoc] or [`eslint-plugin-jsdoc`][plugin:jsdoc] | | [`match-default-export-name`] | πŸ›‘ | N/A | | [`newline-before-return`] | 🌟 | [`padding-line-between-statements`][padding-line-between-statements] [1] | | [`newline-per-chained-call`] | 🌟 | [`newline-per-chained-call`][newline-per-chained-call] | | [`new-parens`] | 🌟 | [`new-parens`][new-parens] | -| [`no-angle-bracket-type-assertion`] | βœ… | [`@typescript-eslint/no-angle-bracket-type-assertion`] | +| [`no-angle-bracket-type-assertion`] | βœ… | [`@typescript-eslint/consistent-type-assertions`] | | [`no-boolean-literal-compare`] | πŸ›‘ | N/A | | [`no-consecutive-blank-lines`] | 🌟 | [`no-multiple-empty-lines`][no-multiple-empty-lines] | | [`no-irregular-whitespace`] | 🌟 | [`no-irregular-whitespace`][no-irregular-whitespace] with `skipStrings: false` | @@ -577,6 +577,8 @@ Relevant plugins: [`chai-expect-keywords`](https://github.com/gavinaiken/eslint- [`@typescript-eslint/await-thenable`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/await-thenable.md [`@typescript-eslint/ban-types`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-types.md [`@typescript-eslint/ban-ts-ignore`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-ignore.md +[`@typescript-eslint/consistent-type-definitions`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-definitions.md +[`@typescript-eslint/consistent-type-assertions`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-assertions.md [`@typescript-eslint/explicit-member-accessibility`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md [`@typescript-eslint/member-ordering`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/member-ordering.md [`@typescript-eslint/no-explicit-any`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -593,7 +595,6 @@ Relevant plugins: [`chai-expect-keywords`](https://github.com/gavinaiken/eslint- [`@typescript-eslint/type-annotation-spacing`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/type-annotation-spacing.md [`@typescript-eslint/unified-signatures`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/unified-signatures.md [`@typescript-eslint/no-misused-new`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-misused-new.md -[`@typescript-eslint/no-object-literal-type-assertion`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-object-literal-type-assertion.md [`@typescript-eslint/no-this-alias`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-this-alias.md [`@typescript-eslint/no-extraneous-class`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-extraneous-class.md [`@typescript-eslint/no-unused-vars`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md @@ -604,11 +605,9 @@ Relevant plugins: [`chai-expect-keywords`](https://github.com/gavinaiken/eslint- [`@typescript-eslint/array-type`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/array-type.md [`@typescript-eslint/class-name-casing`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/class-name-casing.md [`@typescript-eslint/interface-name-prefix`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/interface-name-prefix.md -[`@typescript-eslint/no-angle-bracket-type-assertion`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-angle-bracket-type-assertion.md [`@typescript-eslint/no-parameter-properties`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-parameter-properties.md [`@typescript-eslint/member-delimiter-style`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/member-delimiter-style.md [`@typescript-eslint/prefer-for-of`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-for-of.md -[`@typescript-eslint/prefer-interface`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-interface.md [`@typescript-eslint/no-array-constructor`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-array-constructor.md [`@typescript-eslint/prefer-function-type`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-function-type.md [`@typescript-eslint/prefer-readonly`]: https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-readonly.md diff --git a/packages/eslint-plugin/docs/rules/consistent-type-assertions.md b/packages/eslint-plugin/docs/rules/consistent-type-assertions.md new file mode 100644 index 00000000000..b7bda6ceee4 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/consistent-type-assertions.md @@ -0,0 +1,77 @@ +# Enforces consistent usage of type assertions. (consistent-type-assertions) + +## Rule Details + +This rule aims to standardise the use of type assertion style across the codebase. + +## Options + +```ts +type Options = + | { + assertionStyle: 'as' | 'angle-bracket'; + objectLiteralTypeAssertions: 'allow' | 'allow-as-parameter' | 'never'; + } + | { + assertionStyle: 'never'; + }; + +const defaultOptions: Options = { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', +}; +``` + +### assertionStyle + +This option defines the expected assertion style. Valid values for `assertionStyle` are: + +- `as` will enforce that you always use `... as foo`. +- `angle-bracket` will enforce that you always use `...` +- `never` will enforce that you do not do any type casting. + +Most code bases will want to enforce not using `angle-bracket` style because it conflicts with JSX syntax, and is confusing when paired with with generic syntax. + +Some codebases like to go for an extra level of type safety, and ban casts altogether via the `never` option. + +### objectLiteralTypeAssertions + +Always prefer `const x: T = { ... };` to `const x = { ... } as T;` (or similar with angle brackets). The type assertion in the latter case is either unnecessary or will probably hide an error. + +The compiler will warn for excess properties with this syntax, but not missing _required_ fields. For example: `const x: { foo: number } = {};` will fail to compile, but `const x = {} as { foo: number }` will succeed. + +The const assertion `const x = { foo: 1 } as const`, introduced in TypeScript 3.4, is considered beneficial and is ignored by this option. + +Examples of **incorrect** code for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }` (and for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow-as-parameter' }`) + +```ts +const x = { ... } as T; +``` + +Examples of **correct** code for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'never' }`. + +```ts +const x: T = { ... }; +const y = { ... } as any; +const z = { ... } as unknown; +``` + +Examples of **correct** code for `{ assertionStyle: 'as', objectLiteralTypeAssertions: 'allow-as-parameter' }`. + +```ts +const x: T = { ... }; +const y = { ... } as any; +const z = { ... } as unknown; +foo({ ... } as T); +new Clazz({ ... } as T); +function foo() { throw { bar: 5 } as Foo } +``` + +## When Not To Use It + +If you do not want to enforce consistent type assertions. + +## Compatibility + +- TSLint: [no-angle-bracket-type-assertion](https://palantir.github.io/tslint/rules/no-angle-bracket-type-assertion/) +- TSLint: [no-object-literal-type-assertion](https://palantir.github.io/tslint/rules/no-object-literal-type-assertion/) diff --git a/packages/eslint-plugin/src/configs/all.json b/packages/eslint-plugin/src/configs/all.json index cf3f61c69cd..6a87d9f317a 100644 --- a/packages/eslint-plugin/src/configs/all.json +++ b/packages/eslint-plugin/src/configs/all.json @@ -9,6 +9,7 @@ "camelcase": "off", "@typescript-eslint/camelcase": "error", "@typescript-eslint/class-name-casing": "error", + "@typescript-eslint/consistent-type-assertions": "error", "@typescript-eslint/consistent-type-definitions": "error", "@typescript-eslint/explicit-function-return-type": "error", "@typescript-eslint/explicit-member-accessibility": "error", @@ -21,7 +22,6 @@ "@typescript-eslint/member-delimiter-style": "error", "@typescript-eslint/member-naming": "error", "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/no-angle-bracket-type-assertion": "error", "no-array-constructor": "off", "@typescript-eslint/no-array-constructor": "error", "@typescript-eslint/no-empty-function": "error", @@ -39,7 +39,6 @@ "@typescript-eslint/no-misused-promises": "error", "@typescript-eslint/no-namespace": "error", "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-object-literal-type-assertion": "error", "@typescript-eslint/no-parameter-properties": "error", "@typescript-eslint/no-require-imports": "error", "@typescript-eslint/no-this-alias": "error", diff --git a/packages/eslint-plugin/src/configs/base.json b/packages/eslint-plugin/src/configs/base.json index 6f56100a6ae..9b6931ad616 100644 --- a/packages/eslint-plugin/src/configs/base.json +++ b/packages/eslint-plugin/src/configs/base.json @@ -3,7 +3,5 @@ "parserOptions": { "sourceType": "module" }, - "plugins": [ - "@typescript-eslint" - ] + "plugins": ["@typescript-eslint"] } diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts new file mode 100644 index 00000000000..cca9fa52e5c --- /dev/null +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -0,0 +1,158 @@ +import * as util from '../util'; +import { + TSESTree, + AST_NODE_TYPES, +} from '@typescript-eslint/experimental-utils'; + +// intentionally mirroring the options +type MessageIds = + | 'as' + | 'angle-bracket' + | 'never' + | 'unexpectedObjectTypeAssertion'; +// https://github.com/prettier/prettier/issues/4794 +type OptUnion = + | { + assertionStyle: 'as' | 'angle-bracket'; + objectLiteralTypeAssertions?: 'allow' | 'allow-as-parameter' | 'never'; + } + | { + assertionStyle: 'never'; + }; +type Options = [OptUnion]; + +export default util.createRule({ + name: 'consistent-type-assertions', + meta: { + type: 'suggestion', + docs: { + category: 'Best Practices', + description: 'Enforces consistent usage of type assertions.', + recommended: false, + }, + messages: { + as: "Use 'as {{cast}}' instead of '<{{cast}}>'.", + 'angle-bracket': "Use '<{{cast}}>' instead of 'as {{cast}}'.", + never: 'Do not use any type assertions.', + unexpectedObjectTypeAssertion: 'Always prefer const x: T = { ... }.', + }, + schema: [ + { + oneOf: [ + { + type: 'object', + properties: { + assertionStyle: { + enum: ['never'], + }, + }, + additionalProperties: false, + required: ['assertionStyle'], + }, + { + type: 'object', + properties: { + assertionStyle: { + enum: ['as', 'angle-bracket'], + }, + objectLiteralTypeAssertions: { + enum: ['allow', 'allow-as-parameter', 'never'], + }, + }, + additionalProperties: false, + required: ['assertionStyle'], + }, + ], + }, + ], + }, + defaultOptions: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', + }, + ], + create(context, [options]) { + const sourceCode = context.getSourceCode(); + + function reportIncorrectAssertionType( + node: TSESTree.TSTypeAssertion | TSESTree.TSAsExpression, + ) { + const messageId = options.assertionStyle; + context.report({ + node, + messageId, + data: + messageId !== 'never' + ? { cast: sourceCode.getText(node.typeAnnotation) } + : {}, + }); + } + + function checkType(node: TSESTree.TypeNode) { + switch (node.type) { + case AST_NODE_TYPES.TSAnyKeyword: + case AST_NODE_TYPES.TSUnknownKeyword: + return false; + case AST_NODE_TYPES.TSTypeReference: + // Ignore `as const` and `` + return ( + node.typeName.type === AST_NODE_TYPES.Identifier && + node.typeName.name !== 'const' + ); + default: + return true; + } + } + + function checkExpression( + node: TSESTree.TSTypeAssertion | TSESTree.TSAsExpression, + ) { + if ( + options.assertionStyle === 'never' || + options.objectLiteralTypeAssertions === 'allow' || + node.expression.type !== AST_NODE_TYPES.ObjectExpression + ) { + return; + } + if ( + options.objectLiteralTypeAssertions === 'allow-as-parameter' && + node.parent && + (node.parent.type === AST_NODE_TYPES.NewExpression || + node.parent.type === AST_NODE_TYPES.CallExpression || + node.parent.type === AST_NODE_TYPES.ThrowStatement) + ) { + return; + } + + if ( + checkType(node.typeAnnotation) && + node.expression.type === AST_NODE_TYPES.ObjectExpression + ) { + context.report({ + node, + messageId: 'unexpectedObjectTypeAssertion', + }); + } + } + + return { + TSTypeAssertion(node) { + if (options.assertionStyle !== 'angle-bracket') { + reportIncorrectAssertionType(node); + return; + } + + checkExpression(node); + }, + TSAsExpression(node) { + if (options.assertionStyle !== 'as') { + reportIncorrectAssertionType(node); + return; + } + + checkExpression(node); + }, + }; + }, +}); diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 48280664075..cac5172bdf8 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -5,6 +5,7 @@ import banTsIgnore from './ban-ts-ignore'; import banTypes from './ban-types'; import camelcase from './camelcase'; import classNameCasing from './class-name-casing'; +import consistentTypeAssertions from './consistent-type-assertions'; import consistentTypeDefinitions from './consistent-type-definitions'; import explicitFunctionReturnType from './explicit-function-return-type'; import explicitMemberAccessibility from './explicit-member-accessibility'; @@ -69,6 +70,7 @@ export default { 'ban-types': banTypes, camelcase: camelcase, 'class-name-casing': classNameCasing, + 'consistent-type-assertions': consistentTypeAssertions, 'consistent-type-definitions': consistentTypeDefinitions, 'explicit-function-return-type': explicitFunctionReturnType, 'explicit-member-accessibility': explicitMemberAccessibility, diff --git a/packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts b/packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts index 82848a07196..dd4969936cc 100644 --- a/packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts @@ -15,6 +15,8 @@ export default util.createRule({ "Prefer 'as {{cast}}' instead of '<{{cast}}>' when doing type assertions.", }, schema: [], + deprecated: true, + replacedBy: ['consistent-type-assertions'], }, defaultOptions: [], create(context) { diff --git a/packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts b/packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts index f4089655337..78ca7f4988d 100644 --- a/packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts @@ -36,6 +36,8 @@ export default util.createRule({ }, }, ], + deprecated: true, + replacedBy: ['consistent-type-assertions'], }, defaultOptions: [ { diff --git a/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts new file mode 100644 index 00000000000..b631fdda9d4 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts @@ -0,0 +1,302 @@ +import rule from '../../src/rules/consistent-type-assertions'; +import { RuleTester, batchedSingleLineTests } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', +}); + +const ANGLE_BRACKET_TESTS = ` +const x = new Generic(); +const x = b; +const x = [1]; +const x = [1]; +const x = ('string'); +`; +const AS_TESTS = ` +const x = new Generic() as Foo; +const x = b as A; +const x = [1] as readonly number[]; +const x = [1] as const; +const x = ('string') as a | b; +`; +const OBJECT_LITERAL_AS_CASTS = ` +const x = {} as Foo; +`; +const OBJECT_LITERAL_ANGLE_BRACKET_CASTS = ` +const x = >{}; +`; +const OBJECT_LITERAL_ARGUMENT_AS_CASTS = ` +print({ bar: 5 } as Foo) +new print({ bar: 5 } as Foo) +function foo() { throw { bar: 5 } as Foo } +`; +const OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS = ` +print({ bar: 5 }) +new print({ bar: 5 }) +function foo() { throw { bar: 5 } } +`; + +ruleTester.run('consistent-type-assertions', rule, { + valid: [ + ...batchedSingleLineTests({ + code: AS_TESTS, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', + }, + ], + }), + ...batchedSingleLineTests({ + code: ANGLE_BRACKET_TESTS, + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }), + ...batchedSingleLineTests({ + code: `${OBJECT_LITERAL_AS_CASTS.trimRight()}${OBJECT_LITERAL_ARGUMENT_AS_CASTS}`, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow', + }, + ], + }), + ...batchedSingleLineTests({ + code: `${OBJECT_LITERAL_ANGLE_BRACKET_CASTS.trimRight()}${OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS}`, + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow', + }, + ], + }), + ...batchedSingleLineTests({ + code: OBJECT_LITERAL_ARGUMENT_AS_CASTS, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }), + ...batchedSingleLineTests({ + code: OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS, + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + }), + ], + invalid: [ + ...batchedSingleLineTests({ + code: AS_TESTS, + options: [ + { + assertionStyle: 'angle-bracket', + }, + ], + errors: [ + { + messageId: 'angle-bracket', + line: 2, + }, + { + messageId: 'angle-bracket', + line: 3, + }, + { + messageId: 'angle-bracket', + line: 4, + }, + { + messageId: 'angle-bracket', + line: 5, + }, + { + messageId: 'angle-bracket', + line: 6, + }, + ], + }), + ...batchedSingleLineTests({ + code: ANGLE_BRACKET_TESTS, + options: [ + { + assertionStyle: 'as', + }, + ], + errors: [ + { + messageId: 'as', + line: 2, + }, + { + messageId: 'as', + line: 3, + }, + { + messageId: 'as', + line: 4, + }, + { + messageId: 'as', + line: 5, + }, + { + messageId: 'as', + line: 6, + }, + ], + }), + ...batchedSingleLineTests({ + code: AS_TESTS, + options: [ + { + assertionStyle: 'never', + }, + ], + errors: [ + { + messageId: 'never', + line: 2, + }, + { + messageId: 'never', + line: 3, + }, + { + messageId: 'never', + line: 4, + }, + { + messageId: 'never', + line: 5, + }, + { + messageId: 'never', + line: 6, + }, + ], + }), + ...batchedSingleLineTests({ + code: ANGLE_BRACKET_TESTS, + options: [ + { + assertionStyle: 'never', + }, + ], + errors: [ + { + messageId: 'never', + line: 2, + }, + { + messageId: 'never', + line: 3, + }, + { + messageId: 'never', + line: 4, + }, + { + messageId: 'never', + line: 5, + }, + { + messageId: 'never', + line: 6, + }, + ], + }), + ...batchedSingleLineTests({ + code: OBJECT_LITERAL_AS_CASTS, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + errors: [ + { + messageId: 'unexpectedObjectTypeAssertion', + line: 2, + }, + ], + }), + ...batchedSingleLineTests({ + code: OBJECT_LITERAL_ANGLE_BRACKET_CASTS, + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'allow-as-parameter', + }, + ], + errors: [ + { + messageId: 'unexpectedObjectTypeAssertion', + line: 2, + }, + ], + }), + ...batchedSingleLineTests({ + code: `${OBJECT_LITERAL_AS_CASTS.trimRight()}${OBJECT_LITERAL_ARGUMENT_AS_CASTS}`, + options: [ + { + assertionStyle: 'as', + objectLiteralTypeAssertions: 'never', + }, + ], + errors: [ + { + messageId: 'unexpectedObjectTypeAssertion', + line: 2, + }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 3, + }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 4, + }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 5, + }, + ], + }), + ...batchedSingleLineTests({ + code: `${OBJECT_LITERAL_ANGLE_BRACKET_CASTS.trimRight()}${OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS}`, + options: [ + { + assertionStyle: 'angle-bracket', + objectLiteralTypeAssertions: 'never', + }, + ], + errors: [ + { + messageId: 'unexpectedObjectTypeAssertion', + line: 2, + }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 3, + }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 4, + }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 5, + }, + ], + }), + ], +}); diff --git a/packages/experimental-utils/src/eslint-utils/batchedSingleLineTests.ts b/packages/experimental-utils/src/eslint-utils/batchedSingleLineTests.ts index 0812adade32..567378fdd5d 100644 --- a/packages/experimental-utils/src/eslint-utils/batchedSingleLineTests.ts +++ b/packages/experimental-utils/src/eslint-utils/batchedSingleLineTests.ts @@ -36,6 +36,10 @@ function batchedSingleLineTests< ): (ValidTestCase | InvalidTestCase)[] { // eslint counts lines from 1 const lineOffset = options.code[0] === '\n' ? 2 : 1; + const output = + 'output' in options && options.output + ? options.output.trim().split('\n') + : null; return options.code .trim() .split('\n') @@ -45,7 +49,7 @@ function batchedSingleLineTests< 'errors' in options ? options.errors.filter(e => e.line === lineNum) : []; - return { + const returnVal = { ...options, code, errors: errors.map(e => ({ @@ -53,6 +57,13 @@ function batchedSingleLineTests< line: 1, })), }; + if (output && output[i]) { + return { + ...returnVal, + output: output[i], + }; + } + return returnVal; }); } diff --git a/packages/typescript-estree/src/ts-estree/ts-estree.ts b/packages/typescript-estree/src/ts-estree/ts-estree.ts index 8eed48390d0..f079fd68d47 100644 --- a/packages/typescript-estree/src/ts-estree/ts-estree.ts +++ b/packages/typescript-estree/src/ts-estree/ts-estree.ts @@ -1312,7 +1312,7 @@ export interface TSTypeAnnotation extends BaseNode { export interface TSTypeAssertion extends BaseNode { type: AST_NODE_TYPES.TSTypeAssertion; typeAnnotation: TypeNode; - expression: UnaryExpression; + expression: Expression; } export interface TSTypeLiteral extends BaseNode { From a0d57627c8db94263765a851635a9994676dc9e7 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 21 Jul 2019 19:02:57 -0700 Subject: [PATCH 2/3] chore: remove deprecated rules, update readme --- .../docs/rules/consistent-type-assertions.md | 6 +- .../rules/no-angle-bracket-type-assertion.md | 32 ---- .../rules/no-object-literal-type-assertion.md | 33 ---- packages/eslint-plugin/src/rules/index.ts | 4 - .../rules/no-angle-bracket-type-assertion.ts | 36 ---- .../rules/no-object-literal-type-assertion.ts | 93 ---------- .../no-angle-bracket-type-assertion.test.ts | 164 ------------------ .../no-object-literal-type-assertion.test.ts | 100 ----------- 8 files changed, 4 insertions(+), 464 deletions(-) delete mode 100644 packages/eslint-plugin/docs/rules/no-angle-bracket-type-assertion.md delete mode 100644 packages/eslint-plugin/docs/rules/no-object-literal-type-assertion.md delete mode 100644 packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts delete mode 100644 packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts delete mode 100644 packages/eslint-plugin/tests/rules/no-angle-bracket-type-assertion.test.ts delete mode 100644 packages/eslint-plugin/tests/rules/no-object-literal-type-assertion.test.ts diff --git a/packages/eslint-plugin/docs/rules/consistent-type-assertions.md b/packages/eslint-plugin/docs/rules/consistent-type-assertions.md index b7bda6ceee4..8e619c430ea 100644 --- a/packages/eslint-plugin/docs/rules/consistent-type-assertions.md +++ b/packages/eslint-plugin/docs/rules/consistent-type-assertions.md @@ -4,6 +4,8 @@ This rule aims to standardise the use of type assertion style across the codebase. +Type assertions are also commonly referred as "type casting" in TypeScript (even though it is technically slightly different to what is understood by type casting in other languages), so you can think of type assertions and type casting referring to the same thing. It is essentially you saying to the TypeScript compiler, "in this case, I know better than you!". + ## Options ```ts @@ -28,11 +30,11 @@ This option defines the expected assertion style. Valid values for `assertionSty - `as` will enforce that you always use `... as foo`. - `angle-bracket` will enforce that you always use `...` -- `never` will enforce that you do not do any type casting. +- `never` will enforce that you do not do any type assertions. Most code bases will want to enforce not using `angle-bracket` style because it conflicts with JSX syntax, and is confusing when paired with with generic syntax. -Some codebases like to go for an extra level of type safety, and ban casts altogether via the `never` option. +Some codebases like to go for an extra level of type safety, and ban assertions altogether via the `never` option. ### objectLiteralTypeAssertions diff --git a/packages/eslint-plugin/docs/rules/no-angle-bracket-type-assertion.md b/packages/eslint-plugin/docs/rules/no-angle-bracket-type-assertion.md deleted file mode 100644 index 68cf1591a75..00000000000 --- a/packages/eslint-plugin/docs/rules/no-angle-bracket-type-assertion.md +++ /dev/null @@ -1,32 +0,0 @@ -# Enforces the use of `as Type` assertions instead of `` assertions (no-angle-bracket-type-assertion) - -TypeScript disallows the use of `` assertions in `.tsx` because of the similarity with -JSX's syntax, which makes it impossible to parse. - -## Rule Details - -This rule aims to standardise the use of type assertion style across the codebase - -The following patterns are considered warnings: - -```ts -const foo = bar; -``` - -The following patterns are not warnings: - -```ts -const foo = bar as Foo; -``` - -## When Not To Use It - -If your codebase does not include `.tsx` files, then you will not need this rule. - -## Further Reading - -- [Typescript and JSX](https://www.typescriptlang.org/docs/handbook/jsx.html) - -## Compatibility - -- TSLint: [no-angle-bracket-type-assertion](https://palantir.github.io/tslint/rules/no-angle-bracket-type-assertion/) diff --git a/packages/eslint-plugin/docs/rules/no-object-literal-type-assertion.md b/packages/eslint-plugin/docs/rules/no-object-literal-type-assertion.md deleted file mode 100644 index 044c68aa57f..00000000000 --- a/packages/eslint-plugin/docs/rules/no-object-literal-type-assertion.md +++ /dev/null @@ -1,33 +0,0 @@ -# Forbids an object literal to appear in a type assertion expression (no-object-literal-type-assertion) - -Always prefer `const x: T = { ... };` to `const x = { ... } as T;`. Casting to `any` and `unknown` is still allowed, and const assertions (`as const`) are still allowed. - -## Rule Details - -Examples of **incorrect** code for this rule. - -```ts -const x = { ... } as T; -``` - -Examples of **correct** code for this rule. - -```ts -const x: T = { ... }; -const y = { ... } as any; -const z = { ... } as unknown; -``` - -## Options - -```cjson -{ - "@typescript-eslint/no-object-literal-type-assertion": ["error", { - allowAsParameter: false // Allow type assertion in call and new expression, default false - }] -} -``` - -## Compatibility - -- TSLint: [no-object-literal-type-assertion](https://palantir.github.io/tslint/rules/no-object-literal-type-assertion/) diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index cac5172bdf8..101a2fdc461 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -16,7 +16,6 @@ import interfaceNamePrefix from './interface-name-prefix'; import memberDelimiterStyle from './member-delimiter-style'; import memberNaming from './member-naming'; import memberOrdering from './member-ordering'; -import noAngleBracketTypeAssertion from './no-angle-bracket-type-assertion'; import noArrayConstructor from './no-array-constructor'; import noEmptyFunction from './no-empty-function'; import noEmptyInterface from './no-empty-interface'; @@ -31,7 +30,6 @@ import noMisusedNew from './no-misused-new'; import noMisusedPromises from './no-misused-promises'; import noNamespace from './no-namespace'; import noNonNullAssertion from './no-non-null-assertion'; -import noObjectLiteralTypeAssertion from './no-object-literal-type-assertion'; import noParameterProperties from './no-parameter-properties'; import noRequireImports from './no-require-imports'; import noThisAlias from './no-this-alias'; @@ -81,7 +79,6 @@ export default { 'member-delimiter-style': memberDelimiterStyle, 'member-naming': memberNaming, 'member-ordering': memberOrdering, - 'no-angle-bracket-type-assertion': noAngleBracketTypeAssertion, 'no-array-constructor': noArrayConstructor, 'no-empty-function': noEmptyFunction, 'no-empty-interface': noEmptyInterface, @@ -96,7 +93,6 @@ export default { 'no-misused-promises': noMisusedPromises, 'no-namespace': noNamespace, 'no-non-null-assertion': noNonNullAssertion, - 'no-object-literal-type-assertion': noObjectLiteralTypeAssertion, 'no-parameter-properties': noParameterProperties, 'no-require-imports': noRequireImports, 'no-this-alias': noThisAlias, diff --git a/packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts b/packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts deleted file mode 100644 index dd4969936cc..00000000000 --- a/packages/eslint-plugin/src/rules/no-angle-bracket-type-assertion.ts +++ /dev/null @@ -1,36 +0,0 @@ -import * as util from '../util'; - -export default util.createRule({ - name: 'no-angle-bracket-type-assertion', - meta: { - type: 'problem', - docs: { - description: - 'Enforces the use of `as Type` assertions instead of `` assertions', - category: 'Stylistic Issues', - recommended: 'error', - }, - messages: { - preferAs: - "Prefer 'as {{cast}}' instead of '<{{cast}}>' when doing type assertions.", - }, - schema: [], - deprecated: true, - replacedBy: ['consistent-type-assertions'], - }, - defaultOptions: [], - create(context) { - const sourceCode = context.getSourceCode(); - return { - TSTypeAssertion(node) { - context.report({ - node, - messageId: 'preferAs', - data: { - cast: sourceCode.getText(node.typeAnnotation), - }, - }); - }, - }; - }, -}); diff --git a/packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts b/packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts deleted file mode 100644 index 78ca7f4988d..00000000000 --- a/packages/eslint-plugin/src/rules/no-object-literal-type-assertion.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { - AST_NODE_TYPES, - TSESTree, -} from '@typescript-eslint/experimental-utils'; -import * as util from '../util'; - -type Options = [ - { - allowAsParameter?: boolean; - } -]; -type MessageIds = 'unexpectedTypeAssertion'; - -export default util.createRule({ - name: 'no-object-literal-type-assertion', - meta: { - type: 'problem', - docs: { - description: - 'Forbids an object literal to appear in a type assertion expression', - category: 'Stylistic Issues', - recommended: 'error', - }, - messages: { - unexpectedTypeAssertion: - 'Type assertion on object literals is forbidden, use a type annotation instead.', - }, - schema: [ - { - type: 'object', - additionalProperties: false, - properties: { - allowAsParameter: { - type: 'boolean', - }, - }, - }, - ], - deprecated: true, - replacedBy: ['consistent-type-assertions'], - }, - defaultOptions: [ - { - allowAsParameter: false, - }, - ], - create(context, [{ allowAsParameter }]) { - /** - * Check whatever node should be reported - * @param node the node to be evaluated. - */ - function checkType(node: TSESTree.TypeNode): boolean { - switch (node.type) { - case AST_NODE_TYPES.TSAnyKeyword: - case AST_NODE_TYPES.TSUnknownKeyword: - return false; - case AST_NODE_TYPES.TSTypeReference: - // Ignore `as const` and `` (#166) - return ( - node.typeName.type === AST_NODE_TYPES.Identifier && - node.typeName.name !== 'const' - ); - default: - return true; - } - } - - return { - 'TSTypeAssertion, TSAsExpression'( - node: TSESTree.TSTypeAssertion | TSESTree.TSAsExpression, - ) { - if ( - allowAsParameter && - node.parent && - (node.parent.type === AST_NODE_TYPES.NewExpression || - node.parent.type === AST_NODE_TYPES.CallExpression) - ) { - return; - } - - if ( - checkType(node.typeAnnotation) && - node.expression.type === AST_NODE_TYPES.ObjectExpression - ) { - context.report({ - node, - messageId: 'unexpectedTypeAssertion', - }); - } - }, - }; - }, -}); diff --git a/packages/eslint-plugin/tests/rules/no-angle-bracket-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-angle-bracket-type-assertion.test.ts deleted file mode 100644 index 1d8bd4b2321..00000000000 --- a/packages/eslint-plugin/tests/rules/no-angle-bracket-type-assertion.test.ts +++ /dev/null @@ -1,164 +0,0 @@ -import rule from '../../src/rules/no-angle-bracket-type-assertion'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', -}); - -ruleTester.run('no-angle-bracket-type-assertion', rule, { - valid: [ - ` -interface Foo { - bar : number; - bas : string; -} - -class Generic implements Foo {} - -const foo = {} as Foo; -const bar = new Generic() as Foo; - `, - 'const array : Array = [];', - ` -class A {} -class B extends A {} - -const b : B = new B(); -const a : A = b as A; - `, - ` -type A = { - num: number -}; - -const b = { - num: 5 -}; - -const a: A = b as A; - `, - 'const a : number = 5 as number', - ` -const a : number = 5; -const b : number = a as number; - `, - 'const a : Array = [1] as Array;', - ], - invalid: [ - { - code: ` -interface Foo { - bar : number; - bas : string; -} - -class Generic implements Foo {} - -const foo = {}; -const bar = new Generic(); - `, - errors: [ - { - messageId: 'preferAs', - data: { - cast: 'Foo', - }, - line: 9, - column: 13, - }, - { - messageId: 'preferAs', - data: { - cast: 'Foo', - }, - line: 10, - column: 13, - }, - ], - }, - { - code: 'const a : number = 5', - errors: [ - { - messageId: 'preferAs', - data: { - cast: 'number', - }, - line: 1, - column: 20, - }, - ], - }, - { - code: ` -const a : number = 5; -const b : number = a; - `, - errors: [ - { - messageId: 'preferAs', - data: { - cast: 'number', - }, - line: 3, - column: 20, - }, - ], - }, - { - code: 'const a : Array = >[1];', - errors: [ - { - messageId: 'preferAs', - data: { - cast: 'Array', - }, - line: 1, - column: 27, - }, - ], - }, - { - code: ` -class A {} -class B extends A {} - -const b : B = new B(); -const a : A = b; - `, - errors: [ - { - messageId: 'preferAs', - data: { - cast: 'A', - }, - line: 6, - column: 15, - }, - ], - }, - { - code: ` -type A = { - num: number -}; - -const b = { - num: 5 -}; - -const a: A = b; - `, - errors: [ - { - messageId: 'preferAs', - data: { - cast: 'A', - }, - line: 10, - column: 14, - }, - ], - }, - ], -}); diff --git a/packages/eslint-plugin/tests/rules/no-object-literal-type-assertion.test.ts b/packages/eslint-plugin/tests/rules/no-object-literal-type-assertion.test.ts deleted file mode 100644 index 336df4c29a1..00000000000 --- a/packages/eslint-plugin/tests/rules/no-object-literal-type-assertion.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import rule from '../../src/rules/no-object-literal-type-assertion'; -import { RuleTester } from '../RuleTester'; - -const ruleTester = new RuleTester({ - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 6, - sourceType: 'module', - ecmaFeatures: { - jsx: false, - }, - }, -}); - -ruleTester.run('no-object-literal-type-assertion', rule, { - valid: [ - ` x;`, - `x as T;`, - `const foo = bar;`, - `const foo: baz = bar;`, - `const x: T = {};`, - `const foo = { bar: { } };`, - // Allow cast to 'any' - `const foo = {} as any;`, - `const foo = {};`, - // Allow cast to 'unknown' - `const foo = {} as unknown;`, - `const foo = {};`, - `const foo = {} as const;`, - `const foo = {};`, - { - code: `print({ bar: 5 } as Foo)`, - options: [ - { - allowAsParameter: true, - }, - ], - }, - { - code: `new print({ bar: 5 } as Foo)`, - options: [ - { - allowAsParameter: true, - }, - ], - }, - ], - invalid: [ - { - code: ` ({});`, - errors: [ - { - messageId: 'unexpectedTypeAssertion', - line: 1, - column: 1, - }, - ], - }, - { - code: `({}) as T;`, - errors: [ - { - messageId: 'unexpectedTypeAssertion', - line: 1, - column: 1, - }, - ], - }, - { - code: `const x = {} as T;`, - errors: [ - { - messageId: 'unexpectedTypeAssertion', - line: 1, - column: 11, - }, - ], - }, - { - code: `print({ bar: 5 } as Foo)`, - errors: [ - { - messageId: 'unexpectedTypeAssertion', - line: 1, - column: 7, - }, - ], - }, - { - code: `new print({ bar: 5 } as Foo)`, - errors: [ - { - messageId: 'unexpectedTypeAssertion', - line: 1, - column: 11, - }, - ], - }, - ], -}); From d1186135f9fc88925d6b86714652421e54568a2a Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Wed, 24 Jul 2019 15:55:04 -0700 Subject: [PATCH 3/3] fix: update recommended so lint passes --- packages/eslint-plugin/src/configs/base.json | 4 +++- packages/eslint-plugin/src/configs/recommended.json | 3 +-- .../eslint-plugin/src/rules/consistent-type-assertions.ts | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin/src/configs/base.json b/packages/eslint-plugin/src/configs/base.json index 9b6931ad616..6f56100a6ae 100644 --- a/packages/eslint-plugin/src/configs/base.json +++ b/packages/eslint-plugin/src/configs/base.json @@ -3,5 +3,7 @@ "parserOptions": { "sourceType": "module" }, - "plugins": ["@typescript-eslint"] + "plugins": [ + "@typescript-eslint" + ] } diff --git a/packages/eslint-plugin/src/configs/recommended.json b/packages/eslint-plugin/src/configs/recommended.json index d26fd25d01c..fd48b52510c 100644 --- a/packages/eslint-plugin/src/configs/recommended.json +++ b/packages/eslint-plugin/src/configs/recommended.json @@ -7,13 +7,13 @@ "camelcase": "off", "@typescript-eslint/camelcase": "error", "@typescript-eslint/class-name-casing": "error", + "@typescript-eslint/consistent-type-assertions": "error", "@typescript-eslint/explicit-function-return-type": "warn", "@typescript-eslint/explicit-member-accessibility": "error", "indent": "off", "@typescript-eslint/indent": "error", "@typescript-eslint/interface-name-prefix": "error", "@typescript-eslint/member-delimiter-style": "error", - "@typescript-eslint/no-angle-bracket-type-assertion": "error", "no-array-constructor": "off", "@typescript-eslint/no-array-constructor": "error", "@typescript-eslint/no-empty-interface": "error", @@ -22,7 +22,6 @@ "@typescript-eslint/no-misused-new": "error", "@typescript-eslint/no-namespace": "error", "@typescript-eslint/no-non-null-assertion": "error", - "@typescript-eslint/no-object-literal-type-assertion": "error", "@typescript-eslint/no-parameter-properties": "error", "@typescript-eslint/no-triple-slash-reference": "error", "no-unused-vars": "off", diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts index cca9fa52e5c..6380f9f0003 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -28,7 +28,7 @@ export default util.createRule({ docs: { category: 'Best Practices', description: 'Enforces consistent usage of type assertions.', - recommended: false, + recommended: 'error', }, messages: { as: "Use 'as {{cast}}' instead of '<{{cast}}>'.",