vue-class-component : 调用类方法时 TS2339
Posted
技术标签:
【中文标题】vue-class-component : 调用类方法时 TS2339【英文标题】:vue-class-component : TS2339 when calling class method 【发布时间】:2019-10-20 18:56:36 【问题描述】:我正在使用 vue-cli-service 来构建我的 vuejs 应用程序。
构建成功,但在 webstorm IDE 中,我得到一些 TS2339 错误:
Test.vue:
<template>
<div>method()</div>
</template>
<script lang="ts">
import Component, Vue from 'vue-property-decorator';
@Component
export default class Test extends Vue
public method(): string
return 'hello';
</script>
Test.spec.ts:
import 'jest';
import mount from '@vue/test-utils';
import Test from '@/views/common/Test.vue';
describe('Test.vue', () =>
let wrapper: any;
beforeEach(() =>
wrapper = mount(Test);
);
test('test method call', () =>
const test = wrapper.find(Test).vm as Test;
expect(test.method()).toEqual('hello');
);
);
在 Test.spec.ts 中,我在编辑器和打字稿窗口中都收到此错误:
错误:(14, 21) TS2339:“Vue”类型上不存在属性“方法”。
但是测试没问题,所以test.method()
在运行时解析成功。
【问题讨论】:
您是否缺少类型定义? 类定义不应该足够吗?您会在此处添加哪些额外定义? 你想用 'const value = new Test().value' 达到什么目的?看起来您正在尝试注入依赖项或在本地注册组件,但都没有按照您尝试的方式完成。 当然,这个例子没有任何意义,这只是一个简单的例子来说明问题。更一般地说,我有一个类实例,我想在这个对象上获取一个属性/调用一个方法。 如果您提供一个显示您实际尝试实现的目标的最小示例,而不是无意义的示例,您将节省大量时间。听起来像这样可能是重复的:***.com/questions/46928713/… 【参考方案1】:在通话前添加这些内容。
// tslint:disable-next-line
// @ts-ignore
你也可以像这样联合现有的Test接口:
const test = wrapper.find(Test).vm as Test & method();
并不是说你应该在实践中这样做,但你的代码会运行......
解决此问题的正确方法是augment
Vue's
定义,因此typescript
将接受您的方法。但这应该由 Vue 自动发生。 您是否包含shims-vue.d.ts
文件。这就是打字稿魔法发生的地方?
https://vuejs.org/v2/guide/typescript.html
话虽如此,我在使用 Vue 类语法时遇到了问题,不得不恢复到老式语法以避免打字稿抱怨:
<script lang="ts">
import Vue from 'vue';
export default Vue.extend(
methods:
method(): string
return 'hello';
)
</script>
shims 文件是 Vue 使用您的组件增强自身的方式。
shims-vue.d.ts
declare module '*.vue'
import Vue from 'vue';
export default Vue;
多个 Vue 实例
有时Vue
包含在多个来源中,这会弄乱打字稿。
尝试将此添加到您的 tsconfig
文件中。
"paths":
"@/*": [
"src/*"
],
"vue/*": [
"node_modules/vue/*"
]
有时我什至不得不为此添加 webpack 别名(不过,这将是一个已发布的建筑物,因此不能解决您的问题):
'vue$': path.resolve(__dirname, 'node_modules', 'vue/dist/vue.esm.js'),
【讨论】:
似乎并不令人满意。我不想忽略错误,因为我不想编译 test.unexistingMethod()。关于扩充 Vue 的定义,这不是一个选项。可能老式语法会起作用,这让我认为这是一个 vue-class-component 问题。我创建了一个问题:github.com/vuejs/vue-class-component/issues/340 我有 shims-vue.d.ts,但不确定是否使用过。我应该如何处理这个文件? 也许你的 tsconfig 文件不包括它。 不是……但我会调查一下 事实上,shims 似乎将所有 vue 组件声明为 Vue 实例:github.com/vuejs/vue-class-component/issues/…【参考方案2】:根据 Steven 的回答,我了解到 shims-vue.d.ts 是使用组件作为打字稿类所必需的。但问题是它们都被视为 Vue 实例。 查看此文件内容时,这一点很明显:
declare module '*.vue'
import Vue from 'vue';
export default Vue;
目前,我发现的唯一干净的方法是声明一个由我的组件实现的接口:
model.ts:
export interface ITest
method(): void;
Test.vue:
<template>
<div>method()</div>
</template>
<script lang="ts">
import Component from 'vue-property-decorator';
import Vue from 'vue';
import ITest from '@/views/test/model';
@Component
export default class Test extends Vue implements ITest
public method(): string
return 'hello';
</script>
Test.spec.ts:
import 'jest';
import mount from '@vue/test-utils';
import ITest from '@/views/test/model';
import Test from '@/views/test/Test.vue';
describe('Test.vue', () =>
let wrapper: any;
beforeEach(() =>
wrapper = mount(Test);
);
test('test method call', () =>
const test = wrapper.find(Test).vm as ITest;
expect(test.method()).toEqual('hello');
);
);
【讨论】:
【参考方案3】:我注意到 Vue 文件能够使用其他 Vue 文件作为其声明的类,这促使我尝试将 Jest 文件也声明为 Vue 组件。令人惊讶的是,它有效 - 不需要额外的仅测试接口。
有两个步骤。首先,在您的package.json
中将.vue
后缀添加到Jest 的测试配置中:
"jest":
"testMatch": [
"**/__tests__/**/*.test.ts",
"**/__tests__/**/*.test.vue"
],
其次,将您的测试文件重命名为 .test.vue
并将它们包装在 <script>
块中:
<script lang="ts">
import 'jest';
import shallowMount from '@vue/test-utils';
// Tests here...
</script>
现在您可以使用wrapper.vm
作为实际声明的组件类类型,Vetur/Typescript 将在 IDE 和编译器输出中完全满意。
【讨论】:
以上是关于vue-class-component : 调用类方法时 TS2339的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 vue-class-component 使用 Vue Router 延迟加载?
vue-class-component:如何创建和初始化反射数据
Vuelidate 与 Vue 3 + vue-class-component + TypeScript
vue-class-component 以class的模式写vue组件
[Vue @Component] Simplify Vue Components with vue-class-component