问题
I'm using vue-cli-service to build my vuejs application.
The build is successful, but in webstorm IDE, I get some TS2339 errors :
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');
});
});
In Test.spec.ts, I get this error, both in editor and in typescript window:
Error:(14, 21) TS2339: Property 'method' does not exist on type 'Vue'.
But the test is OK, so test.method()
is resolved successfully at runtime.
回答1:
Add these before your call.
// tslint:disable-next-line
// @ts-ignore
You can also union the existing Test interface like this:
const test = wrapper.find(Test).vm as Test & {method()};
Not to say you should do this in practice, but your code will run...
The correct way to do fix this is to augment
Vue's
definition so typescript
will accept your method. But that should be happening automatically by Vue. Are you including the shims-vue.d.ts
file. That's where the typescript magic happens?
https://vuejs.org/v2/guide/typescript.html
With that said, I have had issues using the Vue class syntax and have had to revert to oldschool syntax to avoid typescript complaining:
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
methods: {
method(): string {
return 'hello';
}
})
</script>
The shims file is how Vue augments itself with your components.
shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
Multiple Vue Instances
Sometimes Vue
is included from multiple sources and this messes up typescript.
Try adding this to your tsconfig
file.
{
"paths": {
"@/*": [
"src/*"
],
"vue/*": [
"node_modules/vue/*"
]
}
I have sometimes even had to add webpack alias for this (this would be an issued building though, so not a fix for your issue):
'vue$': path.resolve(__dirname, 'node_modules', 'vue/dist/vue.esm.js'),
回答2:
Based on Steven's answer, I understood that shims-vue.d.ts is necessary to use component as typescript classes. But the problem is that they are all considered as Vue instances. This is obvious when looking at this file contents:
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
For now, the only clean way I found is to declare an interface implemented by my component:
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:
I noticed that Vue files are able to use other Vue files as their declared classes, which led me to try declaring the Jest files as Vue components as well. Surprisingly, it worked - no additional test-only interfaces required.
There are two steps. First, add the .vue
suffix to Jest's test configuration in your package.json
:
{
"jest": {
"testMatch": [
"**/__tests__/**/*.test.ts",
"**/__tests__/**/*.test.vue"
],
}
}
Second, rename your test files to .test.vue
and wrap them in a <script>
block:
<script lang="ts">
import 'jest';
import { shallowMount } from '@vue/test-utils';
// Tests here...
</script>
Now you can use wrapper.vm
as the actual declared component class type, and Vetur/Typescript will be completely happy in both, the IDE and the compiler output.
来源:https://stackoverflow.com/questions/56457527/vue-class-component-ts2339-when-calling-class-method