Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(eslint-plugin): add new rule prefer-as-const (#1431)
- Loading branch information
1 parent
7fabd97
commit 420db96
Showing
14 changed files
with
342 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# 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. | ||
|
||
## 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 foo = 'bar' as const; | ||
let foo: 'bar' = 'bar' as const; | ||
let bar = 'bar' as string; | ||
let foo = <string>'bar'; | ||
let foo = { bar: 'baz' }; | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
If you are using typescript < 3.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { | ||
AST_NODE_TYPES, | ||
TSESLint, | ||
TSESTree, | ||
} from '@typescript-eslint/experimental-utils'; | ||
import * as util from '../util'; | ||
|
||
export default util.createRule({ | ||
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: { | ||
preferConstAssertion: | ||
'Expected a `const` instead of a literal type assertion', | ||
variableConstAssertion: | ||
'Expected a `const` assertion instead of a literal type annotation', | ||
variableSuggest: 'You should use `as const` instead of type annotation.', | ||
}, | ||
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 | ||
) { | ||
if (canFix) { | ||
context.report({ | ||
node: typeNode, | ||
messageId: 'preferConstAssertion', | ||
fix: fixer => fixer.replaceText(typeNode, 'const'), | ||
}); | ||
} else { | ||
context.report({ | ||
node: typeNode, | ||
messageId: 'variableConstAssertion', | ||
suggest: [ | ||
{ | ||
messageId: 'variableSuggest', | ||
fix: (fixer): TSESLint.RuleFix[] => [ | ||
fixer.remove(typeNode.parent!), | ||
fixer.insertTextAfter(valueNode, ' as const'), | ||
], | ||
}, | ||
], | ||
}); | ||
} | ||
} | ||
} | ||
|
||
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); | ||
} | ||
}, | ||
}; | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
packages/eslint-plugin/tests/rules/prefer-as-const.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
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>'bar';", | ||
"let foo = <string>'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 }', | ||
"let foo: 'baz' = 'baz' as const", | ||
], | ||
invalid: [ | ||
{ | ||
code: "let foo = { bar: 'baz' as 'baz' }", | ||
output: "let foo = { bar: 'baz' as const }", | ||
errors: [ | ||
{ | ||
messageId: 'preferConstAssertion', | ||
line: 1, | ||
column: 27, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: 'let foo = { bar: 1 as 1 }', | ||
output: 'let foo = { bar: 1 as const }', | ||
errors: [ | ||
{ | ||
messageId: 'preferConstAssertion', | ||
line: 1, | ||
column: 23, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: "let []: 'bar' = 'bar';", | ||
output: "let []: 'bar' = 'bar';", | ||
errors: [ | ||
{ | ||
messageId: 'variableConstAssertion', | ||
line: 1, | ||
column: 9, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: "let foo: 'bar' = 'bar';", | ||
output: "let foo: 'bar' = 'bar';", | ||
errors: [ | ||
{ | ||
messageId: 'variableConstAssertion', | ||
line: 1, | ||
column: 10, | ||
suggestions: [ | ||
{ | ||
messageId: 'variableSuggest', | ||
output: "let foo = 'bar' as const;", | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
code: 'let foo: 2 = 2;', | ||
output: 'let foo: 2 = 2;', | ||
errors: [ | ||
{ | ||
messageId: 'variableConstAssertion', | ||
line: 1, | ||
column: 10, | ||
suggestions: [ | ||
{ | ||
messageId: 'variableSuggest', | ||
output: 'let foo = 2 as const;', | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
{ | ||
code: "let foo: 'bar' = 'bar' as 'bar';", | ||
output: "let foo: 'bar' = 'bar' as const;", | ||
errors: [ | ||
{ | ||
messageId: 'preferConstAssertion', | ||
line: 1, | ||
column: 27, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: "let foo = <'bar'>'bar';", | ||
output: "let foo = <const>'bar';", | ||
errors: [ | ||
{ | ||
messageId: 'preferConstAssertion', | ||
line: 1, | ||
column: 12, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: 'let foo = <4>4;', | ||
output: 'let foo = <const>4;', | ||
errors: [ | ||
{ | ||
messageId: 'preferConstAssertion', | ||
line: 1, | ||
column: 12, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: "let foo = 'bar' as 'bar';", | ||
output: "let foo = 'bar' as const;", | ||
errors: [ | ||
{ | ||
messageId: 'preferConstAssertion', | ||
line: 1, | ||
column: 20, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: 'let foo = 5 as 5;', | ||
output: 'let foo = 5 as const;', | ||
errors: [ | ||
{ | ||
messageId: 'preferConstAssertion', | ||
line: 1, | ||
column: 16, | ||
}, | ||
], | ||
}, | ||
], | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.