Search code examples
typescriptvue.jsvuejs2vue-class-components

vue-class-component : TS2339 when calling class method


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.


Solution

  • 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');
        });
    });