From 4864a37cae08533260b5a4e4b927b64523312cce Mon Sep 17 00:00:00 2001 From: Armano Date: Sat, 11 Jan 2020 22:50:11 +0100 Subject: [PATCH 1/9] feat(eslint-plugin): add new rule prefer-as-const --- packages/eslint-plugin/README.md | 5 +- .../docs/rules/prefer-as-const.md | 26 ++++ packages/eslint-plugin/src/configs/all.json | 1 + packages/eslint-plugin/src/rules/index.ts | 2 + .../src/rules/prefer-as-const.ts | 62 ++++++++ .../tests/rules/prefer-as-const.test.ts | 143 ++++++++++++++++++ 6 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 packages/eslint-plugin/docs/rules/prefer-as-const.md create mode 100644 packages/eslint-plugin/src/rules/prefer-as-const.ts create mode 100644 packages/eslint-plugin/tests/rules/prefer-as-const.test.ts diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 0f81cf64216e..3b3170ce6895 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -103,7 +103,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/brace-style`](./docs/rules/brace-style.md) | Enforce consistent brace style for blocks | | :wrench: | | | [`@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/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | | +| [`@typescript-eslint/default-param-last`](./docs/rules/default-param-last.md) | Enforce default parameters to be last | | | | | [`@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 | | | | | [`@typescript-eslint/explicit-module-boundary-types`](./docs/rules/explicit-module-boundary-types.md) | Require explicit return and argument types on exported functions' and classes' public class methods | | | | @@ -123,7 +123,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-extraneous-class`](./docs/rules/no-extraneous-class.md) | Forbids the use of classes as namespaces | | | | | [`@typescript-eslint/no-floating-promises`](./docs/rules/no-floating-promises.md) | Requires Promise-like values to be handled appropriately | | | :thought_balloon: | | [`@typescript-eslint/no-for-in-array`](./docs/rules/no-for-in-array.md) | Disallow iterating over an array with a for-in loop | :heavy_check_mark: | | :thought_balloon: | -| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | | | :thought_balloon:| +| [`@typescript-eslint/no-implied-eval`](./docs/rules/no-implied-eval.md) | Disallow the use of `eval()`-like methods | | | :thought_balloon: | | [`@typescript-eslint/no-inferrable-types`](./docs/rules/no-inferrable-types.md) | Disallows explicit type declarations for variables or parameters initialized to a number, string, or boolean | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-magic-numbers`](./docs/rules/no-magic-numbers.md) | Disallow magic numbers | | | | | [`@typescript-eslint/no-misused-new`](./docs/rules/no-misused-new.md) | Enforce valid definition of `new` and `constructor` | :heavy_check_mark: | | | @@ -145,6 +145,7 @@ Pro Tip: For larger codebases you may want to consider splitting our linting int | [`@typescript-eslint/no-use-before-define`](./docs/rules/no-use-before-define.md) | Disallow the use of variables before they are defined | :heavy_check_mark: | | | | [`@typescript-eslint/no-useless-constructor`](./docs/rules/no-useless-constructor.md) | Disallow unnecessary constructors | | | | | [`@typescript-eslint/no-var-requires`](./docs/rules/no-var-requires.md) | Disallows the use of require statements except in import statements | :heavy_check_mark: | | | +| [`@typescript-eslint/prefer-as-const`](./docs/rules/prefer-as-const.md) | Prefer usage of `as const` over literal type | | :wrench: | | | [`@typescript-eslint/prefer-for-of`](./docs/rules/prefer-for-of.md) | Prefer a ‘for-of’ loop over a standard ‘for’ loop if the index is only used to access the array being iterated | | | | | [`@typescript-eslint/prefer-function-type`](./docs/rules/prefer-function-type.md) | Use function types instead of interfaces with call signatures | | :wrench: | | | [`@typescript-eslint/prefer-includes`](./docs/rules/prefer-includes.md) | Enforce `includes` method over `indexOf` method | :heavy_check_mark: | :wrench: | :thought_balloon: | diff --git a/packages/eslint-plugin/docs/rules/prefer-as-const.md b/packages/eslint-plugin/docs/rules/prefer-as-const.md new file mode 100644 index 000000000000..949ddc8de4be --- /dev/null +++ b/packages/eslint-plugin/docs/rules/prefer-as-const.md @@ -0,0 +1,26 @@ +# Prefer usage of `as const` over literal type assertions (`prefer-as-const`) + +This rule recommends usage of `const` assertion when type primitive value is equal to type. + +## Rule Details + +Examples of **incorrect** code for this rule: + +```ts +let bar: 2 = 2; +let foo = <'bar'>'bar'; +let foo = { bar: 'baz' as 'baz' }; +``` + +Examples of **correct** code for this rule: + +```ts +let foo = 'bar'; +let bar = 'bar' as string; +let foo = 'bar'; +let foo = { bar: 'baz' }; +``` + +## When Not To Use It + +If you are using typescript < 3.4 diff --git a/packages/eslint-plugin/src/configs/all.json b/packages/eslint-plugin/src/configs/all.json index 43dbe291f879..13bbd1f1ccbb 100644 --- a/packages/eslint-plugin/src/configs/all.json +++ b/packages/eslint-plugin/src/configs/all.json @@ -64,6 +64,7 @@ "no-useless-constructor": "off", "@typescript-eslint/no-useless-constructor": "error", "@typescript-eslint/no-var-requires": "error", + "@typescript-eslint/prefer-as-const": "error", "@typescript-eslint/prefer-for-of": "error", "@typescript-eslint/prefer-function-type": "error", "@typescript-eslint/prefer-includes": "error", diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 1caa90bb46ef..97fb654dc248 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -54,6 +54,7 @@ import noUnusedVarsExperimental from './no-unused-vars-experimental'; import noUseBeforeDefine from './no-use-before-define'; import noUselessConstructor from './no-useless-constructor'; import noVarRequires from './no-var-requires'; +import preferAsConst from './prefer-as-const'; import preferForOf from './prefer-for-of'; import preferFunctionType from './prefer-function-type'; import preferIncludes from './prefer-includes'; @@ -136,6 +137,7 @@ export default { 'no-use-before-define': noUseBeforeDefine, 'no-useless-constructor': noUselessConstructor, 'no-var-requires': noVarRequires, + 'prefer-as-const': preferAsConst, 'prefer-for-of': preferForOf, 'prefer-function-type': preferFunctionType, 'prefer-includes': preferIncludes, diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts new file mode 100644 index 000000000000..2a5d5d86b9f2 --- /dev/null +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -0,0 +1,62 @@ +import { + AST_NODE_TYPES, + TSESTree, +} from '@typescript-eslint/experimental-utils'; +import { RuleFix } from '@typescript-eslint/experimental-utils/dist/ts-eslint'; +import * as util from '../util'; + +type MessageIds = 'preferAsConst'; + +export default util.createRule<[], MessageIds>({ + name: 'prefer-as-const', + meta: { + type: 'suggestion', + docs: { + description: 'Prefer usage of `as const` over literal type', + category: 'Best Practices', + recommended: false, + }, + fixable: 'code', + messages: { + preferAsConst: 'Expected a `const` instead of a `type literal`', + }, + schema: [], + }, + defaultOptions: [], + create(context) { + function compareTypes( + valueNode: TSESTree.Expression, + typeNode: TSESTree.TypeNode, + canFix: boolean, + ): void { + if ( + valueNode.type === AST_NODE_TYPES.Literal && + typeNode.type === AST_NODE_TYPES.TSLiteralType && + 'raw' in typeNode.literal && + valueNode.raw === typeNode.literal.raw + ) { + context.report({ + node: typeNode, + messageId: 'preferAsConst', + fix: canFix + ? (fixer): RuleFix => fixer.replaceText(typeNode, 'const') + : undefined, + }); + } + } + + return { + TSAsExpression(node): void { + compareTypes(node.expression, node.typeAnnotation, true); + }, + TSTypeAssertion(node): void { + compareTypes(node.expression, node.typeAnnotation, true); + }, + VariableDeclarator(node): void { + if (node.init && node.id.typeAnnotation) { + compareTypes(node.init, node.id.typeAnnotation.typeAnnotation, false); + } + }, + }; + }, +}); diff --git a/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts new file mode 100644 index 000000000000..351c9041b080 --- /dev/null +++ b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts @@ -0,0 +1,143 @@ +import rule from '../../src/rules/prefer-as-const'; +import { RuleTester } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('prefer-as-const', rule, { + valid: [ + "let foo = 'baz' as const", + 'let foo = 1 as const', + "let foo = { bar: 'baz' as const }", + 'let foo = { bar: 1 as const }', + "let foo = { bar: 'baz' }", + 'let foo = { bar: 2 }', + "let foo = 'bar';", + "let foo = 'bar';", + "let foo = 'bar' as string;", + 'let foo = `bar` as `bar`;', + 'let foo = `bar` as `foo`;', + "let foo = `bar` as 'bar';", + "let foo: string = 'bar';", + 'let foo: number = 1;', + "let foo: 'bar' = baz;", + "let foo = 'bar';", + 'class foo { bar: "baz" = "baz" }', + 'class foo { bar = "baz" }', + "let foo: 'bar'", + 'let foo = { bar }', + ], + invalid: [ + { + code: "let foo = { bar: 'baz' as 'baz' }", + output: "let foo = { bar: 'baz' as const }", + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 27, + }, + ], + }, + { + code: 'let foo = { bar: 1 as 1 }', + output: 'let foo = { bar: 1 as const }', + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 23, + }, + ], + }, + { + code: "let []: 'bar' = 'bar';", + output: "let []: 'bar' = 'bar';", + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 9, + }, + ], + }, + { + code: "let foo: 'bar' = 'bar';", + output: "let foo: 'bar' = 'bar';", + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 10, + }, + ], + }, + { + code: 'let foo: 2 = 2;', + output: 'let foo: 2 = 2;', + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 10, + }, + ], + }, + { + code: "let foo: 'bar' = 'bar' as 'bar';", + output: "let foo: 'bar' = 'bar' as const;", + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 27, + }, + ], + }, + { + code: "let foo = <'bar'>'bar';", + output: "let foo = 'bar';", + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 12, + }, + ], + }, + { + code: 'let foo = <4>4;', + output: 'let foo = 4;', + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 12, + }, + ], + }, + { + code: "let foo = 'bar' as 'bar';", + output: "let foo = 'bar' as const;", + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 20, + }, + ], + }, + { + code: 'let foo = 5 as 5;', + output: 'let foo = 5 as const;', + errors: [ + { + messageId: 'preferAsConst', + line: 1, + column: 16, + }, + ], + }, + ], +}); From 095450f744049fb6897e2165b4f4e5db0912ba3d Mon Sep 17 00:00:00 2001 From: Armano Date: Sat, 11 Jan 2020 23:01:28 +0100 Subject: [PATCH 2/9] chore: apply prefer-as-const rule into project --- .eslintrc.js | 1 + packages/eslint-plugin/src/rules/indent.ts | 4 +- .../tests/rules/no-array-constructor.test.ts | 2 +- .../tests/rules/no-extraneous-class.test.ts | 6 +- .../tests/rules/no-this-alias.test.ts | 6 +- .../tests/rules/no-use-before-define.test.ts | 2 +- packages/parser/tests/lib/parser.ts | 2 +- packages/typescript-estree/src/node-utils.ts | 126 +++++++++--------- 8 files changed, 75 insertions(+), 74 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 4aa35ae4305f..3271a33e83ed 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -33,6 +33,7 @@ module.exports = { '@typescript-eslint/prefer-nullish-coalescing': 'error', '@typescript-eslint/prefer-optional-chain': 'error', '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/prefer-as-const': 'error', 'no-empty-function': 'off', '@typescript-eslint/no-empty-function': [ diff --git a/packages/eslint-plugin/src/rules/indent.ts b/packages/eslint-plugin/src/rules/indent.ts index 9023939ac629..2ef19344d920 100644 --- a/packages/eslint-plugin/src/rules/indent.ts +++ b/packages/eslint-plugin/src/rules/indent.ts @@ -259,7 +259,7 @@ export default util.createRule({ return rules.VariableDeclaration({ type: AST_NODE_TYPES.VariableDeclaration, - kind: 'const' as 'const', + kind: 'const' as const, declarations: [ { type: AST_NODE_TYPES.VariableDeclarator, @@ -388,7 +388,7 @@ export default util.createRule({ ? node.typeAnnotation.loc.end : squareBracketStart.loc.end, }, - kind: 'init' as 'init', + kind: 'init' as const, computed: false, method: false, shorthand: false, diff --git a/packages/eslint-plugin/tests/rules/no-array-constructor.test.ts b/packages/eslint-plugin/tests/rules/no-array-constructor.test.ts index ca3da767f80c..cc6530085ddf 100644 --- a/packages/eslint-plugin/tests/rules/no-array-constructor.test.ts +++ b/packages/eslint-plugin/tests/rules/no-array-constructor.test.ts @@ -6,7 +6,7 @@ const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -const messageId = 'useLiteral' as 'useLiteral'; +const messageId = 'useLiteral' as const; ruleTester.run('no-array-constructor', rule, { valid: [ diff --git a/packages/eslint-plugin/tests/rules/no-extraneous-class.test.ts b/packages/eslint-plugin/tests/rules/no-extraneous-class.test.ts index e009aa153ae8..88d558e711a8 100644 --- a/packages/eslint-plugin/tests/rules/no-extraneous-class.test.ts +++ b/packages/eslint-plugin/tests/rules/no-extraneous-class.test.ts @@ -3,13 +3,13 @@ import rule from '../../src/rules/no-extraneous-class'; import { RuleTester } from '../RuleTester'; const empty = { - messageId: 'empty' as 'empty', + messageId: 'empty' as const, }; const onlyStatic = { - messageId: 'onlyStatic' as 'onlyStatic', + messageId: 'onlyStatic' as const, }; const onlyConstructor = { - messageId: 'onlyConstructor' as 'onlyConstructor', + messageId: 'onlyConstructor' as const, }; const ruleTester = new RuleTester({ diff --git a/packages/eslint-plugin/tests/rules/no-this-alias.test.ts b/packages/eslint-plugin/tests/rules/no-this-alias.test.ts index 03723eb9515d..0cbd35dae19f 100644 --- a/packages/eslint-plugin/tests/rules/no-this-alias.test.ts +++ b/packages/eslint-plugin/tests/rules/no-this-alias.test.ts @@ -3,15 +3,15 @@ import rule from '../../src/rules/no-this-alias'; import { RuleTester } from '../RuleTester'; const idError = { - messageId: 'thisAssignment' as 'thisAssignment', + messageId: 'thisAssignment' as const, type: AST_NODE_TYPES.Identifier, }; const destructureError = { - messageId: 'thisDestructure' as 'thisDestructure', + messageId: 'thisDestructure' as const, type: AST_NODE_TYPES.ObjectPattern, }; const arrayDestructureError = { - messageId: 'thisDestructure' as 'thisDestructure', + messageId: 'thisDestructure' as const, type: AST_NODE_TYPES.ArrayPattern, }; diff --git a/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts b/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts index 8b375aef075d..9d9434397fd4 100644 --- a/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts +++ b/packages/eslint-plugin/tests/rules/no-use-before-define.test.ts @@ -6,7 +6,7 @@ const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', }); -const parserOptions = { ecmaVersion: 6 as 6 }; +const parserOptions = { ecmaVersion: 6 as const }; ruleTester.run('no-use-before-define', rule, { valid: [ diff --git a/packages/parser/tests/lib/parser.ts b/packages/parser/tests/lib/parser.ts index 56ce08b67862..3881456d2ffd 100644 --- a/packages/parser/tests/lib/parser.ts +++ b/packages/parser/tests/lib/parser.ts @@ -43,7 +43,7 @@ describe('parser', () => { comment: false, range: false, tokens: false, - sourceType: 'module' as 'module', + sourceType: 'module' as const, ecmaVersion: 2018, ecmaFeatures: { globalReturn: false, diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index 77ffca87cc47..5015e8d2e787 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -30,69 +30,69 @@ const LOGICAL_OPERATORS: ( ]; const TOKEN_TO_TEXT = { - [SyntaxKind.OpenBraceToken]: '{' as '{', - [SyntaxKind.CloseBraceToken]: '}' as '}', - [SyntaxKind.OpenParenToken]: '(' as '(', - [SyntaxKind.CloseParenToken]: ')' as ')', - [SyntaxKind.OpenBracketToken]: '[' as '[', - [SyntaxKind.CloseBracketToken]: ']' as ']', - [SyntaxKind.DotToken]: '.' as '.', - [SyntaxKind.DotDotDotToken]: '...' as '...', - [SyntaxKind.SemicolonToken]: ';' as ';', - [SyntaxKind.CommaToken]: ',' as ',', - [SyntaxKind.LessThanToken]: '<' as '<', - [SyntaxKind.GreaterThanToken]: '>' as '>', - [SyntaxKind.LessThanEqualsToken]: '<=' as '<=', - [SyntaxKind.GreaterThanEqualsToken]: '>=' as '>=', - [SyntaxKind.EqualsEqualsToken]: '==' as '==', - [SyntaxKind.ExclamationEqualsToken]: '!=' as '!=', - [SyntaxKind.EqualsEqualsEqualsToken]: '===' as '===', - [SyntaxKind.InstanceOfKeyword]: 'instanceof' as 'instanceof', - [SyntaxKind.ExclamationEqualsEqualsToken]: '!==' as '!==', - [SyntaxKind.EqualsGreaterThanToken]: '=>' as '=>', - [SyntaxKind.PlusToken]: '+' as '+', - [SyntaxKind.MinusToken]: '-' as '-', - [SyntaxKind.AsteriskToken]: '*' as '*', - [SyntaxKind.AsteriskAsteriskToken]: '**' as '**', - [SyntaxKind.SlashToken]: '/' as '/', - [SyntaxKind.PercentToken]: '%' as '%', - [SyntaxKind.PlusPlusToken]: '++' as '++', - [SyntaxKind.MinusMinusToken]: '--' as '--', - [SyntaxKind.LessThanLessThanToken]: '<<' as '<<', - [SyntaxKind.LessThanSlashToken]: '>' as '>>', - [SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: '>>>' as '>>>', - [SyntaxKind.AmpersandToken]: '&' as '&', - [SyntaxKind.BarToken]: '|' as '|', - [SyntaxKind.CaretToken]: '^' as '^', - [SyntaxKind.ExclamationToken]: '!' as '!', - [SyntaxKind.TildeToken]: '~' as '~', - [SyntaxKind.AmpersandAmpersandToken]: '&&' as '&&', - [SyntaxKind.BarBarToken]: '||' as '||', - [SyntaxKind.QuestionToken]: '?' as '?', - [SyntaxKind.ColonToken]: ':' as ':', - [SyntaxKind.EqualsToken]: '=' as '=', - [SyntaxKind.PlusEqualsToken]: '+=' as '+=', - [SyntaxKind.MinusEqualsToken]: '-=' as '-=', - [SyntaxKind.AsteriskEqualsToken]: '*=' as '*=', - [SyntaxKind.AsteriskAsteriskEqualsToken]: '**=' as '**=', - [SyntaxKind.SlashEqualsToken]: '/=' as '/=', - [SyntaxKind.PercentEqualsToken]: '%=' as '%=', - [SyntaxKind.LessThanLessThanEqualsToken]: '<<=' as '<<=', - [SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>=' as '>>=', - [SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>=' as '>>>=', - [SyntaxKind.AmpersandEqualsToken]: '&=' as '&=', - [SyntaxKind.BarEqualsToken]: '|=' as '|=', - [SyntaxKind.CaretEqualsToken]: '^=' as '^=', - [SyntaxKind.AtToken]: '@' as '@', - [SyntaxKind.InKeyword]: 'in' as 'in', - [SyntaxKind.UniqueKeyword]: 'unique' as 'unique', - [SyntaxKind.KeyOfKeyword]: 'keyof' as 'keyof', - [SyntaxKind.NewKeyword]: 'new' as 'new', - [SyntaxKind.ImportKeyword]: 'import' as 'import', - [SyntaxKind.ReadonlyKeyword]: 'readonly' as 'readonly', - [SyntaxKind.QuestionQuestionToken]: '??' as '??', - [SyntaxKind.QuestionDotToken]: '?.' as '?.', + [SyntaxKind.OpenBraceToken]: '{' as const, + [SyntaxKind.CloseBraceToken]: '}' as const, + [SyntaxKind.OpenParenToken]: '(' as const, + [SyntaxKind.CloseParenToken]: ')' as const, + [SyntaxKind.OpenBracketToken]: '[' as const, + [SyntaxKind.CloseBracketToken]: ']' as const, + [SyntaxKind.DotToken]: '.' as const, + [SyntaxKind.DotDotDotToken]: '...' as const, + [SyntaxKind.SemicolonToken]: ';' as const, + [SyntaxKind.CommaToken]: ',' as const, + [SyntaxKind.LessThanToken]: '<' as const, + [SyntaxKind.GreaterThanToken]: '>' as const, + [SyntaxKind.LessThanEqualsToken]: '<=' as const, + [SyntaxKind.GreaterThanEqualsToken]: '>=' as const, + [SyntaxKind.EqualsEqualsToken]: '==' as const, + [SyntaxKind.ExclamationEqualsToken]: '!=' as const, + [SyntaxKind.EqualsEqualsEqualsToken]: '===' as const, + [SyntaxKind.InstanceOfKeyword]: 'instanceof' as const, + [SyntaxKind.ExclamationEqualsEqualsToken]: '!==' as const, + [SyntaxKind.EqualsGreaterThanToken]: '=>' as const, + [SyntaxKind.PlusToken]: '+' as const, + [SyntaxKind.MinusToken]: '-' as const, + [SyntaxKind.AsteriskToken]: '*' as const, + [SyntaxKind.AsteriskAsteriskToken]: '**' as const, + [SyntaxKind.SlashToken]: '/' as const, + [SyntaxKind.PercentToken]: '%' as const, + [SyntaxKind.PlusPlusToken]: '++' as const, + [SyntaxKind.MinusMinusToken]: '--' as const, + [SyntaxKind.LessThanLessThanToken]: '<<' as const, + [SyntaxKind.LessThanSlashToken]: '>' as const, + [SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: '>>>' as const, + [SyntaxKind.AmpersandToken]: '&' as const, + [SyntaxKind.BarToken]: '|' as const, + [SyntaxKind.CaretToken]: '^' as const, + [SyntaxKind.ExclamationToken]: '!' as const, + [SyntaxKind.TildeToken]: '~' as const, + [SyntaxKind.AmpersandAmpersandToken]: '&&' as const, + [SyntaxKind.BarBarToken]: '||' as const, + [SyntaxKind.QuestionToken]: '?' as const, + [SyntaxKind.ColonToken]: ':' as const, + [SyntaxKind.EqualsToken]: '=' as const, + [SyntaxKind.PlusEqualsToken]: '+=' as const, + [SyntaxKind.MinusEqualsToken]: '-=' as const, + [SyntaxKind.AsteriskEqualsToken]: '*=' as const, + [SyntaxKind.AsteriskAsteriskEqualsToken]: '**=' as const, + [SyntaxKind.SlashEqualsToken]: '/=' as const, + [SyntaxKind.PercentEqualsToken]: '%=' as const, + [SyntaxKind.LessThanLessThanEqualsToken]: '<<=' as const, + [SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>=' as const, + [SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>=' as const, + [SyntaxKind.AmpersandEqualsToken]: '&=' as const, + [SyntaxKind.BarEqualsToken]: '|=' as const, + [SyntaxKind.CaretEqualsToken]: '^=' as const, + [SyntaxKind.AtToken]: '@' as const, + [SyntaxKind.InKeyword]: 'in' as const, + [SyntaxKind.UniqueKeyword]: 'unique' as const, + [SyntaxKind.KeyOfKeyword]: 'keyof' as const, + [SyntaxKind.NewKeyword]: 'new' as const, + [SyntaxKind.ImportKeyword]: 'import' as const, + [SyntaxKind.ReadonlyKeyword]: 'readonly' as const, + [SyntaxKind.QuestionQuestionToken]: '??' as const, + [SyntaxKind.QuestionDotToken]: '?.' as const, }; /** From cba487d9e43ffe96137a48267932c209508337dc Mon Sep 17 00:00:00 2001 From: Armano Date: Sat, 11 Jan 2020 23:03:52 +0100 Subject: [PATCH 3/9] chore(typescript-estree): update TOKEN_TO_TEXT --- packages/typescript-estree/src/node-utils.ts | 128 +++++++++---------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index 5015e8d2e787..ffcd0af0b579 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -30,70 +30,70 @@ const LOGICAL_OPERATORS: ( ]; const TOKEN_TO_TEXT = { - [SyntaxKind.OpenBraceToken]: '{' as const, - [SyntaxKind.CloseBraceToken]: '}' as const, - [SyntaxKind.OpenParenToken]: '(' as const, - [SyntaxKind.CloseParenToken]: ')' as const, - [SyntaxKind.OpenBracketToken]: '[' as const, - [SyntaxKind.CloseBracketToken]: ']' as const, - [SyntaxKind.DotToken]: '.' as const, - [SyntaxKind.DotDotDotToken]: '...' as const, - [SyntaxKind.SemicolonToken]: ';' as const, - [SyntaxKind.CommaToken]: ',' as const, - [SyntaxKind.LessThanToken]: '<' as const, - [SyntaxKind.GreaterThanToken]: '>' as const, - [SyntaxKind.LessThanEqualsToken]: '<=' as const, - [SyntaxKind.GreaterThanEqualsToken]: '>=' as const, - [SyntaxKind.EqualsEqualsToken]: '==' as const, - [SyntaxKind.ExclamationEqualsToken]: '!=' as const, - [SyntaxKind.EqualsEqualsEqualsToken]: '===' as const, - [SyntaxKind.InstanceOfKeyword]: 'instanceof' as const, - [SyntaxKind.ExclamationEqualsEqualsToken]: '!==' as const, - [SyntaxKind.EqualsGreaterThanToken]: '=>' as const, - [SyntaxKind.PlusToken]: '+' as const, - [SyntaxKind.MinusToken]: '-' as const, - [SyntaxKind.AsteriskToken]: '*' as const, - [SyntaxKind.AsteriskAsteriskToken]: '**' as const, - [SyntaxKind.SlashToken]: '/' as const, - [SyntaxKind.PercentToken]: '%' as const, - [SyntaxKind.PlusPlusToken]: '++' as const, - [SyntaxKind.MinusMinusToken]: '--' as const, - [SyntaxKind.LessThanLessThanToken]: '<<' as const, - [SyntaxKind.LessThanSlashToken]: '>' as const, - [SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: '>>>' as const, - [SyntaxKind.AmpersandToken]: '&' as const, - [SyntaxKind.BarToken]: '|' as const, - [SyntaxKind.CaretToken]: '^' as const, - [SyntaxKind.ExclamationToken]: '!' as const, - [SyntaxKind.TildeToken]: '~' as const, - [SyntaxKind.AmpersandAmpersandToken]: '&&' as const, - [SyntaxKind.BarBarToken]: '||' as const, - [SyntaxKind.QuestionToken]: '?' as const, - [SyntaxKind.ColonToken]: ':' as const, - [SyntaxKind.EqualsToken]: '=' as const, - [SyntaxKind.PlusEqualsToken]: '+=' as const, - [SyntaxKind.MinusEqualsToken]: '-=' as const, - [SyntaxKind.AsteriskEqualsToken]: '*=' as const, - [SyntaxKind.AsteriskAsteriskEqualsToken]: '**=' as const, - [SyntaxKind.SlashEqualsToken]: '/=' as const, - [SyntaxKind.PercentEqualsToken]: '%=' as const, - [SyntaxKind.LessThanLessThanEqualsToken]: '<<=' as const, - [SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>=' as const, - [SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>=' as const, - [SyntaxKind.AmpersandEqualsToken]: '&=' as const, - [SyntaxKind.BarEqualsToken]: '|=' as const, - [SyntaxKind.CaretEqualsToken]: '^=' as const, - [SyntaxKind.AtToken]: '@' as const, - [SyntaxKind.InKeyword]: 'in' as const, - [SyntaxKind.UniqueKeyword]: 'unique' as const, - [SyntaxKind.KeyOfKeyword]: 'keyof' as const, - [SyntaxKind.NewKeyword]: 'new' as const, - [SyntaxKind.ImportKeyword]: 'import' as const, - [SyntaxKind.ReadonlyKeyword]: 'readonly' as const, - [SyntaxKind.QuestionQuestionToken]: '??' as const, - [SyntaxKind.QuestionDotToken]: '?.' as const, -}; + [SyntaxKind.OpenBraceToken]: '{', + [SyntaxKind.CloseBraceToken]: '}', + [SyntaxKind.OpenParenToken]: '(', + [SyntaxKind.CloseParenToken]: ')', + [SyntaxKind.OpenBracketToken]: '[', + [SyntaxKind.CloseBracketToken]: ']', + [SyntaxKind.DotToken]: '.', + [SyntaxKind.DotDotDotToken]: '...', + [SyntaxKind.SemicolonToken]: ';', + [SyntaxKind.CommaToken]: ',', + [SyntaxKind.LessThanToken]: '<', + [SyntaxKind.GreaterThanToken]: '>', + [SyntaxKind.LessThanEqualsToken]: '<=', + [SyntaxKind.GreaterThanEqualsToken]: '>=', + [SyntaxKind.EqualsEqualsToken]: '==', + [SyntaxKind.ExclamationEqualsToken]: '!=', + [SyntaxKind.EqualsEqualsEqualsToken]: '===', + [SyntaxKind.InstanceOfKeyword]: 'instanceof', + [SyntaxKind.ExclamationEqualsEqualsToken]: '!==', + [SyntaxKind.EqualsGreaterThanToken]: '=>', + [SyntaxKind.PlusToken]: '+', + [SyntaxKind.MinusToken]: '-', + [SyntaxKind.AsteriskToken]: '*', + [SyntaxKind.AsteriskAsteriskToken]: '**', + [SyntaxKind.SlashToken]: '/', + [SyntaxKind.PercentToken]: '%', + [SyntaxKind.PlusPlusToken]: '++', + [SyntaxKind.MinusMinusToken]: '--', + [SyntaxKind.LessThanLessThanToken]: '<<', + [SyntaxKind.LessThanSlashToken]: '>', + [SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: '>>>', + [SyntaxKind.AmpersandToken]: '&', + [SyntaxKind.BarToken]: '|', + [SyntaxKind.CaretToken]: '^', + [SyntaxKind.ExclamationToken]: '!', + [SyntaxKind.TildeToken]: '~', + [SyntaxKind.AmpersandAmpersandToken]: '&&', + [SyntaxKind.BarBarToken]: '||', + [SyntaxKind.QuestionToken]: '?', + [SyntaxKind.ColonToken]: ':', + [SyntaxKind.EqualsToken]: '=', + [SyntaxKind.PlusEqualsToken]: '+=', + [SyntaxKind.MinusEqualsToken]: '-=', + [SyntaxKind.AsteriskEqualsToken]: '*=', + [SyntaxKind.AsteriskAsteriskEqualsToken]: '**=', + [SyntaxKind.SlashEqualsToken]: '/=', + [SyntaxKind.PercentEqualsToken]: '%=', + [SyntaxKind.LessThanLessThanEqualsToken]: '<<=', + [SyntaxKind.GreaterThanGreaterThanEqualsToken]: '>>=', + [SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: '>>>=', + [SyntaxKind.AmpersandEqualsToken]: '&=', + [SyntaxKind.BarEqualsToken]: '|=', + [SyntaxKind.CaretEqualsToken]: '^=', + [SyntaxKind.AtToken]: '@', + [SyntaxKind.InKeyword]: 'in', + [SyntaxKind.UniqueKeyword]: 'unique', + [SyntaxKind.KeyOfKeyword]: 'keyof', + [SyntaxKind.NewKeyword]: 'new', + [SyntaxKind.ImportKeyword]: 'import', + [SyntaxKind.ReadonlyKeyword]: 'readonly', + [SyntaxKind.QuestionQuestionToken]: '??', + [SyntaxKind.QuestionDotToken]: '?.', +} as const; /** * Returns true if the given ts.Token is the assignment operator From 519b811a143a0a297cfd6295b4554d9ddbe1f665 Mon Sep 17 00:00:00 2001 From: Armano Date: Sat, 11 Jan 2020 23:04:39 +0100 Subject: [PATCH 4/9] chore(eslint-plugin): correct doc --- packages/eslint-plugin/docs/rules/prefer-as-const.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/docs/rules/prefer-as-const.md b/packages/eslint-plugin/docs/rules/prefer-as-const.md index 949ddc8de4be..d9f797397d76 100644 --- a/packages/eslint-plugin/docs/rules/prefer-as-const.md +++ b/packages/eslint-plugin/docs/rules/prefer-as-const.md @@ -1,4 +1,4 @@ -# Prefer usage of `as const` over literal type assertions (`prefer-as-const`) +# Prefer usage of `as const` over literal type (`prefer-as-const`) This rule recommends usage of `const` assertion when type primitive value is equal to type. From 9b29bda0ef0d92f02d3da22d4880f2f747ce021c Mon Sep 17 00:00:00 2001 From: Armano Date: Sun, 12 Jan 2020 04:34:20 +0100 Subject: [PATCH 5/9] chore(eslint-plugin): remove unnecessary types --- packages/eslint-plugin/src/rules/prefer-as-const.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index 2a5d5d86b9f2..18904018bc06 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -5,9 +5,7 @@ import { import { RuleFix } from '@typescript-eslint/experimental-utils/dist/ts-eslint'; import * as util from '../util'; -type MessageIds = 'preferAsConst'; - -export default util.createRule<[], MessageIds>({ +export default util.createRule({ name: 'prefer-as-const', meta: { type: 'suggestion', From e7b9c015423760d6d0c9dd2533f3057d4f2ce51e Mon Sep 17 00:00:00 2001 From: Armano Date: Wed, 15 Jan 2020 23:37:02 +0100 Subject: [PATCH 6/9] chore: update messages to better fit context --- .../src/rules/prefer-as-const.ts | 25 ++++++++++++------- .../tests/rules/prefer-as-const.test.ts | 21 ++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index 18904018bc06..b20f5517b374 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -2,7 +2,6 @@ import { AST_NODE_TYPES, TSESTree, } from '@typescript-eslint/experimental-utils'; -import { RuleFix } from '@typescript-eslint/experimental-utils/dist/ts-eslint'; import * as util from '../util'; export default util.createRule({ @@ -16,7 +15,10 @@ export default util.createRule({ }, fixable: 'code', messages: { - preferAsConst: 'Expected a `const` instead of a `type literal`', + preferConstAssertion: + 'Expected a `const` instead of a literal type assertion', + variableConstAssertion: + 'Expected a `const` assertion instead of a literal type annotation', }, schema: [], }, @@ -33,13 +35,18 @@ export default util.createRule({ 'raw' in typeNode.literal && valueNode.raw === typeNode.literal.raw ) { - context.report({ - node: typeNode, - messageId: 'preferAsConst', - fix: canFix - ? (fixer): RuleFix => fixer.replaceText(typeNode, 'const') - : undefined, - }); + if (canFix) { + context.report({ + node: typeNode, + messageId: 'preferConstAssertion', + fix: fixer => fixer.replaceText(typeNode, 'const'), + }); + } else { + context.report({ + node: typeNode, + messageId: 'variableConstAssertion', + }); + } } } diff --git a/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts index 351c9041b080..f22049214785 100644 --- a/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts @@ -27,6 +27,7 @@ ruleTester.run('prefer-as-const', rule, { 'class foo { bar = "baz" }', "let foo: 'bar'", 'let foo = { bar }', + "let foo: 'baz' = 'baz' as const", ], invalid: [ { @@ -34,7 +35,7 @@ ruleTester.run('prefer-as-const', rule, { output: "let foo = { bar: 'baz' as const }", errors: [ { - messageId: 'preferAsConst', + messageId: 'preferConstAssertion', line: 1, column: 27, }, @@ -45,7 +46,7 @@ ruleTester.run('prefer-as-const', rule, { output: 'let foo = { bar: 1 as const }', errors: [ { - messageId: 'preferAsConst', + messageId: 'preferConstAssertion', line: 1, column: 23, }, @@ -56,7 +57,7 @@ ruleTester.run('prefer-as-const', rule, { output: "let []: 'bar' = 'bar';", errors: [ { - messageId: 'preferAsConst', + messageId: 'variableConstAssertion', line: 1, column: 9, }, @@ -67,7 +68,7 @@ ruleTester.run('prefer-as-const', rule, { output: "let foo: 'bar' = 'bar';", errors: [ { - messageId: 'preferAsConst', + messageId: 'variableConstAssertion', line: 1, column: 10, }, @@ -78,7 +79,7 @@ ruleTester.run('prefer-as-const', rule, { output: 'let foo: 2 = 2;', errors: [ { - messageId: 'preferAsConst', + messageId: 'variableConstAssertion', line: 1, column: 10, }, @@ -89,7 +90,7 @@ ruleTester.run('prefer-as-const', rule, { output: "let foo: 'bar' = 'bar' as const;", errors: [ { - messageId: 'preferAsConst', + messageId: 'preferConstAssertion', line: 1, column: 27, }, @@ -100,7 +101,7 @@ ruleTester.run('prefer-as-const', rule, { output: "let foo = 'bar';", errors: [ { - messageId: 'preferAsConst', + messageId: 'preferConstAssertion', line: 1, column: 12, }, @@ -111,7 +112,7 @@ ruleTester.run('prefer-as-const', rule, { output: 'let foo = 4;', errors: [ { - messageId: 'preferAsConst', + messageId: 'preferConstAssertion', line: 1, column: 12, }, @@ -122,7 +123,7 @@ ruleTester.run('prefer-as-const', rule, { output: "let foo = 'bar' as const;", errors: [ { - messageId: 'preferAsConst', + messageId: 'preferConstAssertion', line: 1, column: 20, }, @@ -133,7 +134,7 @@ ruleTester.run('prefer-as-const', rule, { output: 'let foo = 5 as const;', errors: [ { - messageId: 'preferAsConst', + messageId: 'preferConstAssertion', line: 1, column: 16, }, From 1b491d96f35e0645d0f7cc3a6e91e0aded102d22 Mon Sep 17 00:00:00 2001 From: Armano Date: Sat, 18 Jan 2020 20:07:34 +0100 Subject: [PATCH 7/9] feat(eslint-plugin): add suggestions for variables --- .../docs/rules/prefer-as-const.md | 2 ++ .../src/rules/prefer-as-const.ts | 15 ++++++++++++++ .../tests/rules/prefer-as-const.test.ts | 20 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/packages/eslint-plugin/docs/rules/prefer-as-const.md b/packages/eslint-plugin/docs/rules/prefer-as-const.md index d9f797397d76..bb288192d267 100644 --- a/packages/eslint-plugin/docs/rules/prefer-as-const.md +++ b/packages/eslint-plugin/docs/rules/prefer-as-const.md @@ -16,6 +16,8 @@ Examples of **correct** code for this rule: ```ts let foo = 'bar'; +let foo = 'bar' as const; +let foo: 'bar' = 'bar' as const; let bar = 'bar' as string; let foo = 'bar'; let foo = { bar: 'baz' }; diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index b20f5517b374..635bb4bb4e1e 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -19,6 +19,8 @@ export default util.createRule({ 'Expected a `const` instead of a literal type assertion', variableConstAssertion: 'Expected a `const` assertion instead of a literal type annotation', + variableSuggest1: 'You should add `as const` assertion.', + variableSuggest2: 'You should use `as const` instead of type annotation.', }, schema: [], }, @@ -45,6 +47,19 @@ export default util.createRule({ context.report({ node: typeNode, messageId: 'variableConstAssertion', + suggest: [ + { + messageId: 'variableSuggest1', + fix: fixer => fixer.insertTextAfter(valueNode, ' as const'), + }, + { + messageId: 'variableSuggest2', + fix: fixer => [ + fixer.remove(typeNode.parent!), + fixer.insertTextAfter(valueNode, ' as const'), + ], + }, + ], }); } } diff --git a/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts index f22049214785..8587ea034157 100644 --- a/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts @@ -71,6 +71,16 @@ ruleTester.run('prefer-as-const', rule, { messageId: 'variableConstAssertion', line: 1, column: 10, + suggestions: [ + { + messageId: 'variableSuggest1', + output: "let foo: 'bar' = 'bar' as const;", + }, + { + messageId: 'variableSuggest2', + output: "let foo = 'bar' as const;", + }, + ], }, ], }, @@ -82,6 +92,16 @@ ruleTester.run('prefer-as-const', rule, { messageId: 'variableConstAssertion', line: 1, column: 10, + suggestions: [ + { + messageId: 'variableSuggest1', + output: 'let foo: 2 = 2 as const;', + }, + { + messageId: 'variableSuggest2', + output: 'let foo = 2 as const;', + }, + ], }, ], }, From 57ba6ff24985b0f155ac490f9a9f278881461f8e Mon Sep 17 00:00:00 2001 From: Armano Date: Sat, 18 Jan 2020 20:20:41 +0100 Subject: [PATCH 8/9] chore: fix linting error --- packages/eslint-plugin/src/rules/prefer-as-const.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index 635bb4bb4e1e..ca32b7c05570 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -1,5 +1,6 @@ import { AST_NODE_TYPES, + TSESLint, TSESTree, } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; @@ -50,11 +51,12 @@ export default util.createRule({ suggest: [ { messageId: 'variableSuggest1', - fix: fixer => fixer.insertTextAfter(valueNode, ' as const'), + fix: (fixer): TSESLint.RuleFix => + fixer.insertTextAfter(valueNode, ' as const'), }, { messageId: 'variableSuggest2', - fix: fixer => [ + fix: (fixer): TSESLint.RuleFix[] => [ fixer.remove(typeNode.parent!), fixer.insertTextAfter(valueNode, ' as const'), ], From 132112e85432cf9fa5ed8add4ee6b2eaa61b920d Mon Sep 17 00:00:00 2001 From: Armano Date: Tue, 21 Jan 2020 01:38:07 +0100 Subject: [PATCH 9/9] chore(eslint-plugin): remove one suggestion from rule --- packages/eslint-plugin/src/rules/prefer-as-const.ts | 10 ++-------- .../tests/rules/prefer-as-const.test.ts | 12 ++---------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-as-const.ts b/packages/eslint-plugin/src/rules/prefer-as-const.ts index ca32b7c05570..1cf21af7580c 100644 --- a/packages/eslint-plugin/src/rules/prefer-as-const.ts +++ b/packages/eslint-plugin/src/rules/prefer-as-const.ts @@ -20,8 +20,7 @@ export default util.createRule({ 'Expected a `const` instead of a literal type assertion', variableConstAssertion: 'Expected a `const` assertion instead of a literal type annotation', - variableSuggest1: 'You should add `as const` assertion.', - variableSuggest2: 'You should use `as const` instead of type annotation.', + variableSuggest: 'You should use `as const` instead of type annotation.', }, schema: [], }, @@ -50,12 +49,7 @@ export default util.createRule({ messageId: 'variableConstAssertion', suggest: [ { - messageId: 'variableSuggest1', - fix: (fixer): TSESLint.RuleFix => - fixer.insertTextAfter(valueNode, ' as const'), - }, - { - messageId: 'variableSuggest2', + messageId: 'variableSuggest', fix: (fixer): TSESLint.RuleFix[] => [ fixer.remove(typeNode.parent!), fixer.insertTextAfter(valueNode, ' as const'), diff --git a/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts index 8587ea034157..c18ac5d7f14b 100644 --- a/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-as-const.test.ts @@ -73,11 +73,7 @@ ruleTester.run('prefer-as-const', rule, { column: 10, suggestions: [ { - messageId: 'variableSuggest1', - output: "let foo: 'bar' = 'bar' as const;", - }, - { - messageId: 'variableSuggest2', + messageId: 'variableSuggest', output: "let foo = 'bar' as const;", }, ], @@ -94,11 +90,7 @@ ruleTester.run('prefer-as-const', rule, { column: 10, suggestions: [ { - messageId: 'variableSuggest1', - output: 'let foo: 2 = 2 as const;', - }, - { - messageId: 'variableSuggest2', + messageId: 'variableSuggest', output: 'let foo = 2 as const;', }, ],