-
-
Notifications
You must be signed in to change notification settings - Fork 679
Add vue/require-typed-ref
rule
#2204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
9b4f0cf
Initial implementation of require-typed-ref rule
Demivan a18ff99
Improve type detection
Demivan 4097a97
Add filename check
Demivan a59ff1a
Fix eslint warnings
Demivan 2eb0f6a
Improve error messages
Demivan cab4092
Add documentation
Demivan 4989f9c
Add requireExplicitType option
Demivan c0c6932
Fix docs build
Demivan 13ceb18
Add options to docs
Demivan 5f1b9a8
Do not check other functions
Demivan 5424b74
Fix extension check
Demivan 5c5bc62
Add check for literal null and undefined
Demivan 66195e9
Apply suggestions from code review
Demivan 15b8da3
Add option explanation
Demivan 6e72b92
Add defineComponent with setup function tests
Demivan 129916f
Apply suggestions from code review
Demivan 6350bab
Remove `requireExplicitType` option
Demivan 36711a8
Apply suggestions from code review
Demivan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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,56 @@ | ||
--- | ||
pageClass: rule-details | ||
sidebarDepth: 0 | ||
title: vue/require-typed-ref | ||
description: require `ref` and `shallowRef` functions to be strongly typed | ||
--- | ||
# vue/require-typed-ref | ||
|
||
> require `ref` and `shallowRef` functions to be strongly typed | ||
|
||
- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> ***This rule has not been released yet.*** </badge> | ||
|
||
## :book: Rule Details | ||
|
||
This rule disallows calling `ref()` or `shallowRef()` functions without generic type parameter or an argument when using TypeScript. | ||
|
||
With TypeScript it is easy to prevent usage of `any` by using [`noImplicitAny`](https://www.typescriptlang.org/tsconfig#noImplicitAny). Unfortunately this rule is easily bypassed with Vue `ref()` function. Calling `ref()` function without a generic parameter or an initial value leads to ref having `Ref<any>` type. | ||
|
||
<eslint-code-block :rules="{'vue/require-typed-ref': ['error']}"> | ||
|
||
```vue | ||
<script setup lang="ts"> | ||
import { ref, shallowRef, type Ref } from 'vue' | ||
|
||
/* ✗ BAD */ | ||
const count = ref() // Returns Ref<any> that is not type checked | ||
count.value = '50' // Should be a type error, but it is not | ||
|
||
const count = shallowRef() | ||
|
||
/* ✓ GOOD */ | ||
const count = ref<number>() | ||
const count = ref(0) | ||
const count: Ref<number | undefined> = ref() | ||
</script> | ||
``` | ||
|
||
</eslint-code-block> | ||
|
||
## :wrench: Options | ||
|
||
```json | ||
{ | ||
"vue/require-typed-ref": ["error", { | ||
"requireExplicitType": false | ||
}] | ||
} | ||
``` | ||
|
||
- `requireExplicitType` ... If `true`, requires `ref` and `shallowRef` functions to have type specified, even if there is a argument. Requires to write `const count = ref<number>(0)`. | ||
default `false` | ||
|
||
## :mag: Implementation | ||
|
||
- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-typed-ref.js) | ||
- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-typed-ref.js) |
This file contains hidden or 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 hidden or 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,119 @@ | ||
/** | ||
* @author Ivan Demchuk <https://github.com/Demivan> | ||
* See LICENSE file in root directory for full license. | ||
*/ | ||
'use strict' | ||
|
||
const { iterateDefineRefs } = require('../utils/ref-object-references') | ||
const utils = require('../utils') | ||
|
||
/** | ||
* @param {Expression|SpreadElement} node | ||
*/ | ||
function isNullOrUndefined(node) { | ||
if (node.type === 'Literal' && node.value === null) { | ||
return true | ||
} | ||
|
||
if (node.type === 'Identifier' && node.name === 'undefined') { | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
/** | ||
* @typedef {import('../utils/ref-object-references').RefObjectReferences} RefObjectReferences | ||
*/ | ||
|
||
module.exports = { | ||
meta: { | ||
type: 'suggestion', | ||
docs: { | ||
description: | ||
'require `ref` and `shallowRef` functions to be strongly typed', | ||
categories: undefined, | ||
url: 'https://eslint.vuejs.org/rules/require-typed-ref.html' | ||
}, | ||
fixable: null, | ||
messages: { | ||
noType: | ||
'Specify type parameter for `{{name}}` function, otherwise created variable will not by typechecked.' | ||
}, | ||
schema: [ | ||
{ | ||
type: 'object', | ||
properties: { | ||
requireExplicitType: { | ||
type: 'boolean' | ||
} | ||
}, | ||
additionalProperties: false | ||
} | ||
] | ||
}, | ||
/** @param {RuleContext} context */ | ||
create(context) { | ||
const { requireExplicitType = false } = context.options[0] ?? {} | ||
|
||
const filename = context.getFilename() | ||
if (!utils.isVueFile(filename) && !utils.isTypeScriptFile(filename)) { | ||
return {} | ||
} | ||
|
||
const scriptSetup = utils.getScriptSetupElement(context) | ||
if ( | ||
scriptSetup && | ||
!utils.hasAttribute(scriptSetup, 'lang', 'ts') && | ||
!utils.hasAttribute(scriptSetup, 'lang', 'typescript') | ||
) { | ||
return {} | ||
} | ||
|
||
const defines = iterateDefineRefs(context.getScope()) | ||
|
||
/** | ||
* @param {string} name | ||
* @param {CallExpression} node | ||
*/ | ||
function report(name, node) { | ||
context.report({ | ||
node, | ||
messageId: 'noType', | ||
data: { | ||
name | ||
} | ||
}) | ||
} | ||
|
||
return { | ||
Program() { | ||
for (const ref of defines) { | ||
if (ref.name !== 'ref' && ref.name !== 'shallowRef') { | ||
continue | ||
} | ||
|
||
if ( | ||
ref.node.arguments.length > 0 && | ||
!isNullOrUndefined(ref.node.arguments[0]) && | ||
!requireExplicitType | ||
) { | ||
continue | ||
} | ||
|
||
if (ref.node.typeParameters == null) { | ||
if ( | ||
ref.node.parent.type === 'VariableDeclarator' && | ||
ref.node.parent.id.type === 'Identifier' | ||
) { | ||
if (ref.node.parent.id.typeAnnotation == null) | ||
report(ref.name, ref.node) | ||
Demivan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else { | ||
report(ref.name, ref.node) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains hidden or 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 hidden or 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.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.