Tim Hutchison
Tim Hutchison

Reputation: 3633

Resolve "Property does not exist on type 'Vue'" error

I am using Typescript with Vuejs to build an application. I have several stand alone components (.vue) files that I am importing into a Typescript (.ts) file. In the Typescript file, I am importing Vue from the npm Vue library and then creating a new Vue to display my components. The error that I am seeing is:

Property x does not exist on type 'Vue'

My build system is Webpack with tsc. Why am I getting this error and how can I resolve it?

main.ts

import Vue from 'vue';
import Competency from '../components/competency.vue';

new Vue({
  el: "#app",
  components: {
    'competency': Competency
  },
  data:{
    count: 0
  },
  methods:{
    initialize: function(){
      this.count = count + 1; // Errors here with Property count does not exist on type vue
    }
  }
})

tsconfig

{
  "compilerOptions": {
    // "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "lib": [
      "es2015",
      "dom",
      "es2015.promise"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "noEmitOnError": true,
    "noImplicitAny": false,
    //"outDir": "./build/",
    "removeComments": false,
    "sourceMap": true,
    "target": "es5"

  },
  "exclude": [
    "./node_modules",
    "wwwroot",
    "./Model"
  ],
  "include": [
    "./CCSEQ",
    "./WebResources"
  ]
}

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
    entry: {
        Evaluations: './WebResources/js/main.ts'
    },
    devServer: {
        contentBase: './dist'
    },
    module: {
        rules: [{
                test: /\.ts$/,
                exclude: /node_modules|vue\/src/,
                loader: 'ts-loader',
                exclude: /node_modules/,
                options: {
                    appendTsSuffixTo: [/\.vue$/]
                }
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    esModule: true
                }
            },
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    'file-loader'
                ]
            },
        ]
    },
    resolve: {
        extensions: [".tsx", ".ts", ".js"],
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            filename: 'Evaluations.html',
            template: './WebResources/html/Evaluations.html'
        }), new HtmlWebpackPlugin({
            filename: 'ExpenseUpload.html',
            template: './WebResources/html/ExpenseUpload.html'
        }), new webpack.optimize.CommonsChunkPlugin({
            name: 'WebAPI'
        })
    ],
    output: {
        filename: '[name].bundle.js',
        path: path.resolve(__dirname, 'dist')
    }
}

Upvotes: 51

Views: 124424

Answers (14)

s00103898-276165-15433
s00103898-276165-15433

Reputation: 988

Have the same issue. Solution is to add a return type on each computed variable.

Issue from this code, without return type.

  computed: {
    containerClass() {
      return this.isLastChild
    },
  },

Adding the return type String:

  computed: {
    containerClass(): String {
      return this.isLastChild
    },
  },

Upvotes: 9

immi10
immi10

Reputation: 109

In VSCode this was fixed for me by quitting VSCode completely and opening it again.

Upvotes: 0

Jakub Kurdziel
Jakub Kurdziel

Reputation: 3762

I had the same problem but with exporting a component. Some vs code snippets create templates without necessary types like this below

export default {
  data() {
    return {
      x: "something",
    };
  },
  methods: {
    rename(name: string) {
      this.x = name;
    },
    
  },
};

The problem was I did not add defineComponent() to export default. So should be


import { defineComponent } from "vue";

export default defineComponent({
  data() {
    return {
      x: "something",
    };
  },
  methods: {
    rename(name: string) {
      this.x = name;
    },
    
  },
});

Make sure you are exporting the component with the defineComponent() function.

Upvotes: 30

ProfDFrancis
ProfDFrancis

Reputation: 9411

Adding another answer to bring together several things you may need to fix.

Ensure you include the ".vue" extension in the filename being imported

While both

import Competency from '../components/competency';

and

import Competency from '../components/competency.vue';

may compile successfully, the second one will help avoid the error appearing in some IDE's such as VS Code.

Add a shim typings file

As @May pointed out above, you need a file that imports and re-exports the type of "Vue". In @May's answer, it is named vue-file-import.d.ts, but elsewhere on the internet it is commonly called vue-shim.d.ts. Regardless of name, the content needed is the same:

// vue-file-import.d.ts

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

Try different locations for the shim file

Originally I put it in /src. I found this had an odd effect. Sometimes it worked, i.e. the VS Code error messages disappeared; and other times it didn't, they reappeared. This happened dynamically as I moved around the project editing different files.

I later found the suggestion for a shim file of identical content, but to be placed in /typings. I tried this and it worked consistently. Other people seem quite happy with the /src location.

Upvotes: 10

reggaeguitar
reggaeguitar

Reputation: 1804

I was trying to follow this page https://v2.vuejs.org/v2/guide/routing.html and was getting the same TypeScript errors, I fixed it by casting the Vue instance to type any like this

    new Vue({
        el: '#app',
        data: {
            currentRoute: window.location.pathname
        },
        computed: {
            ViewComponent() {
                return routes[(this as any).currentRoute] || routes['/']
            }
        },
        render (h) { return h((this as any).ViewComponent) }
    })

Upvotes: 2

Nico Nicolas
Nico Nicolas

Reputation: 11

If you are using typescript & vue2, you should use Vue.component or Vue.extend to define component.

import Vue from 'vue'
const Component = Vue.extend({
  ...
})

Upvotes: 1

Orange
Orange

Reputation: 71

@sherwin water's answer help me a lot. I recognized that, once I added a computed field, the error appears. The solution is simple: add return type for the computed field.

// wrong
computed: {
  someThing() {
    const { a, b } = this;
    return a + b;
  }
}

// correct
computed: {
  someThing(): number {
    const { a, b } = this;
    return a + b;
  }
}

Upvotes: 6

Piece
Piece

Reputation: 828

I faced this error when I'm using VS Code editor.

I've installed Vetur plugin on vs code, Vetur handles vue file as typescript file, so I've fixed it to edit settings.json file

Please find this file on your VS editor in your project root directory, then set change like the below enter image description here

"vetur.experimental.templateInterpolationService": false

It works for me

Upvotes: 0

xmasuhai
xmasuhai

Reputation: 9

do not use any

use Object.assign(vm, source); instead

like

const source= {count: this.count }
Object.assign(this, source);

Upvotes: 0

Avraham Appel
Avraham Appel

Reputation: 36

Try using Typescript's generics. See https://www.typescriptlang.org/docs/handbook/generics.html

new Vue<{ count: number }, { initialize: () => void }, {}, {}>({

  //...

  data:{
    count: 0
  },

  methods:{
    initialize: function() {
      this.count = count + 1;
    },
  }
});

Upvotes: -1

Buksy
Buksy

Reputation: 12228

I suggest using class based components when using typescript (have a look at this "Writing Class-Based Components with Vue.js and TypeScript"). This is the only way to have type safe code and use autocomplete functionality of your IDE

You need to install vue-property-decorator

Here is an example of class based component:

import { Component, Vue, Watch } from 'vue-property-decorator'

@Component({
  props: {
    prop1: { type: Number }
  }
})
export default class MyComponent extends Vue {
  // This is how you define computed
  get myComputedRoute() {
     return this.$route.params;
  }

  @Watch('myComputedRoute')
  onPropertyChanged(value: string, oldValue: string) {
    // Do stuff with the watcher here.
  }
}

Upvotes: 1

ArniqueMK
ArniqueMK

Reputation: 69

I got the same errors with vue 2.8.2 and Typescript 2.5.3. I fixed it by holding my Vue instance in a variable then giving it a type. This ensures TS will know about all Vue properties when you instatiate it using an options object.

var VueApp: any = Vue;

var App = new VueApp({
  el: "#app",
  data() {
     return {
        count: 0
     }
  },
  methods:{
    initialize() {
      this.count = count + 1; // Should work now
    }
  }
})

Upvotes: 0

PuncrOc
PuncrOc

Reputation: 1

I ran into similar problems (especially in .vue files). I did find that this seemed to fix the problem however. Anywhere you import .vue files, change the ES6 style "import" to "require" instead.

So in your example, change:

import Competency from '../components/competency.vue';

to...

declare var require: any;
var Competency = require("../components/competency.vue").default;

Upvotes: 0

may
may

Reputation: 114

you should make a declare for import *.vue file.

such as:

vue-file-import.d.ts

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

Upvotes: 9

Related Questions