@azsxdc12356/eslint-plugin-vue-ref-value
v1.0.6
Published
ESLint plugin to detect missing .value when using Vue ref variables
Maintainers
Readme
eslint-plugin-vue-ref-value
ESLint 插件,用于检测 Vue2 项目中使用 ref 定义的变量在实际使用时未使用 .value 的问题。
安装
# npm
npm install @azsxdc12356/eslint-plugin-vue-ref-value --save-dev
# yarn
yarn add @azsxdc12356/eslint-plugin-vue-ref-value -D
# pnpm
pnpm add @azsxdc12356/eslint-plugin-vue-ref-value -D使用
ESLint 9+(推荐)
// eslint.config.js
const vueRefValue = require('@azsxdc12356/eslint-plugin-vue-ref-value');
module.exports = [
{
plugins: {
'@azsxdc12356/vue-ref-value': vueRefValue
},
rules: {
'@azsxdc12356/vue-ref-value/require-ref-value': 'error'
}
}
];ESLint 8 及以下
// .eslintrc.js
module.exports = {
plugins: ['@azsxdc12356/vue-ref-value'],
rules: {
'@azsxdc12356/vue-ref-value/require-ref-value': 'error'
}
}已知限制
跨文件 ref 变量检测
ESLint 是静态分析工具,只能分析当前文件的作用域。无法检测从其他文件导入的 ref 变量:
// useCounter.js
export function useCounter() {
const count = ref(0);
return { count }; // 返回 ref 变量
}
// MyComponent.vue
import { useCounter } from './useCounter';
const { count } = useCounter();
console.log(count); // ❌ 检测不到 count 是 ref,不会报错!解决方案:
- 使用命名约定(推荐):配置
namingConventions: ['Ref'],使用countRef命名 - 类型标注:使用 TypeScript 配合类型检查
功能特性
自动跳过检测的场景
| 场景 | 说明 |
|------|------|
| .value 访问 | count.value ✅ |
| Vue 模板 | <template> 中自动解包 |
| 返回值 | return count、return { count }、return [count] |
| reactive 对象 | reactive({ count: ref(0) }) 中的 state.count |
| 白名单函数 | watch(count, ...)、isRef(count) 等 |
| 作用域遮蔽 | 局部同名变量遮蔽外部 ref |
白名单函数
默认允许直接传入 ref 的函数:
watch、watchEffect、watchPostEffect、watchSyncEffect、isRef、unref、toRef、toRefs、toValue、triggerRef、shallowRef、computed、readonly、markRaw、ref、inject、provide
自定义白名单
rules: {
'@azsxdc12356/vue-ref-value/require-ref-value': ['error', {
allowlistFunctions: ['myCustomFunction']
}]
}命名约定检测(跨文件 ref 变量)
对于从其他文件导入的 ref 变量(如 composables),由于 ESLint 无法跨文件分析,可以通过命名约定来检测:
// eslint.config.js
module.exports = {
rules: {
'@azsxdc12356/vue-ref-value/require-ref-value': ['error', {
namingConventions: ['Ref', 'Computed'] // 以 Ref 或 Computed 结尾的变量需要 .value
}]
}
};使用示例:
// useUser.js (其他文件)
export function useUser() {
const userRef = ref({ name: 'John' }); // 命名约定:以 Ref 结尾
return { userRef };
}
// MyComponent.vue
import { useUser } from './useUser';
const { userRef } = useUser();
console.log(userRef); // ❌ 错误:命名约定变量需要 .value
console.log(userRef.value); // ✅ 正确
// 函数调用不会被检测(排除 getter 函数)
function getUserRef() { return ref({}); }
const user = getUserRef(); // ✅ 正确:函数调用不受命名约定影响命名约定规则:
- 变量名以指定后缀结尾(如
userRef,totalComputed) - 排除函数调用:
getUserRef()不会被检测 - 遵循其他所有规则(白名单、返回值、defineExpose 等)
示例
基本用法
import { ref } from 'vue';
const count = ref(0);
console.log(count); // ❌ 错误:缺少 .value
console.log(count.value); // ✅ 正确
count.value = 1; // ✅ 正确:赋值
if (count > 0) { } // ❌ 错误
if (count.value > 0) { } // ✅ 正确别名导入
import { ref as r } from 'vue';
const count = r(0);
console.log(count); // ❌ 错误
console.log(count.value); // ✅ 正确Vue 模板自动解包
<template>
<div>{{ count }}</div> <!-- ✅ 正确:template 中自动解包 -->
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const count = ref(0);
console.log(count); // ❌ 错误:script 中需要 .value
console.log(count.value); // ✅ 正确
return { count }; // ✅ 正确:返回值
}
}
</script>白名单函数
import { ref, watch, isRef, unref } from 'vue';
const count = ref(0);
watch(count, () => {}); // ✅ 正确
isRef(count); // ✅ 正确
unref(count); // ✅ 正确返回值
import { ref } from 'vue';
function useCounter() {
const count = ref(0);
return count; // ✅ 正确:直接返回
}
function useCounter() {
const count = ref(0);
return { count }; // ✅ 正确:返回对象
}
function useCounter() {
const count = ref(0);
return [count]; // ✅ 正确:返回数组
}
function useCounter() {
const count = ref(0);
return count + 1; // ❌ 错误:参与运算需要 .value
}reactive 自动解包
import { ref, reactive } from 'vue';
const count = ref(0);
const state = reactive({ count });
console.log(state.count); // ✅ 正确:reactive 自动解包
state.count = 1; // ✅ 正确
// 别名导入
import { reactive as r } from 'vue';
const state2 = r({ count: ref(0) });
console.log(state2.count); // ✅ 正确作用域遮蔽
import { ref } from 'vue';
const count = ref(0);
function test() {
const count = 123; // 局部变量遮蔽外部 ref
console.log(count); // ✅ 正确:这是局部变量
}
function test(count) { // 参数遮蔽
return count; // ✅ 正确:这是参数
}
console.log(count); // ❌ 错误:外部的 ref 需要 .value自定义白名单
// eslint.config.js
module.exports = {
rules: {
'@azsxdc12356/vue-ref-value/require-ref-value': ['error', {
allowlistFunctions: ['myCustomFunction']
}]
}
};
// 代码中
import { ref } from 'vue';
const count = ref(0);
myCustomFunction(count); // ✅ 正确:自定义白名单License
MIT
