简体   繁体   English

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

[英]vue-class-component : TS2339 when calling class method

I'm using vue-cli-service to build my vuejs application.我正在使用 vue-cli-service 来构建我的 vuejs 应用程序。

The build is successful, but in webstorm IDE, I get some TS2339 errors :构建成功,但在 webstorm IDE 中,我收到一些 TS2339 错误:

Test.vue:测试.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:在 Test.spec.ts 中,我在编辑器和打字稿窗口中都收到此错误:

Error:(14, 21) TS2339: Property 'method' does not exist on type 'Vue'.错误:(14, 21) TS2339:“Vue”类型上不存在属性“方法”。

But the test is OK, so test.method() is resolved successfully at runtime.但是测试没问题,所以test.method()在运行时解析成功。

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.解决此问题的正确方法是augment Vue's定义,以便typescript接受您的方法。 But that should be happening automatically by Vue.但这应该由 Vue 自动发生。 Are you including the shims-vue.d.ts file.您是否包括shims-vue.d.ts文件。 That's where the typescript magic happens?那就是打字稿魔术发生的地方?

https://v2.vuejs.org/v2/guide/typescript.html https://v2.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:话虽如此,我在使用 Vue 类语法时遇到了问题,不得不恢复到老式语法以避免打字稿抱怨:

<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 如何使用您的组件增强自身的方式。

shims-vue.d.ts shims-vue.d.ts

declare module '*.vue' {
  import Vue from 'vue';
  export default Vue;

Multiple Vue Instances多个 Vue 实例

Sometimes Vue is included from multiple sources and this messes up typescript.有时Vue包含在多个来源中,这会弄乱打字稿。

Try adding this to your tsconfig file.尝试将此添加到您的tsconfig文件中。

{
    "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):我有时甚至不得不为此添加 webpack 别名(尽管这将是一个已发布的建筑物,因此不能解决您的问题):

        'vue$': path.resolve(__dirname, 'node_modules', 'vue/dist/vue.esm.js'),

Based on Steven's answer, I understood that shims-vue.d.ts is necessary to use component as typescript classes.根据史蒂文的回答,我了解到 shims-vue.d.ts 是使用组件作为打字稿类所必需的。 But the problem is that they are all considered as Vue instances.但问题是它们都被视为 Vue 实例。 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:模型.ts:

export interface ITest {
    method(): void;
}

Test.vue:测试.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');
    });
});

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.我注意到 Vue 文件能够使用其他 Vue 文件作为它们声明的类,这导致我尝试将 Jest 文件也声明为 Vue 组件。 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 :首先,在你的package.json中将.vue后缀添加到 Jest 的测试配置中:

{
  "jest": {
    "testMatch": [
      "**/__tests__/**/*.test.ts",
      "**/__tests__/**/*.test.vue"
    ],
  }
}

Second, rename your test files to .test.vue and wrap them in a <script> block:其次,将您的测试文件重命名为.test.vue并将它们包装在<script>块中:

<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.现在您可以使用wrapper.vm作为实际声明的组件类类型,并且 Vetur/Typescript 在 IDE 和编译器输出中都将完全满意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM