vue-class-component:调用类方法时为TS2339

时间:2019-06-05 09:14:08

标签: typescript vue.js vuejs2 vue-class-components

我正在使用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'不存在属性'method'。

但是测试还可以,因此test.method()已在运行时成功解决。

3 个答案:

答案 0 :(得分:0)

在通话前添加这些内容。

// 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'),

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我注意到Vue文件能够将其他Vue文件用作其声明的类,这导致我尝试将Jest文件也声明为Vue组件。令人惊讶的是,它可以正常工作-不需要其他仅测试界面。

有两个步骤。首先,将.vue后缀添加到package.json中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和编译器输出中将完全满意。