Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In the TypeScript component, the error Property does not exist on type 'Vue' #8406

Closed
weihongyu12 opened this issue Jun 25, 2018 · 9 comments

Comments

@weihongyu12
Copy link

weihongyu12 commented Jun 25, 2018

Version

2.5.16

Reproduction link

https://codesandbox.io/s/github/weihongyu12/vue-typescript-demo

Steps to reproduce

Uses @vue/cli to build the project. The configuration uses TypeScript. However, in the process of using, in the methods, there is no access to the computed. The construction does not exist on type 'Vue'.

<template>
  <ul
    v-if="show"
    class="picker">
    <li
      v-for="(item, index) of pickerList"
      :key="index">{{ item }}</li>
  </ul>
</template>

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
  name : 'Picker',
  props: {
    columns: {
      type: Array,
      default: [],
    },
    show: {
      type: Boolean ,
      default: false,
    },
  },
  computed: {
    pickerList(): Array<string> {
      const arr = [];
      const columns: any = this.columns;
      for (const item of columns) {
        arr.push(item.title);
      }
      return arr;
    },
    pickerMap() : Map<string, number> {
      const map = new Map();
      const columns: any = this.columns;
      for (const item of columns) {
        map.set(item.title, item.id);
      }
      return map;
    },
  },
  methods: {
    onConfirm(value: string): void {
      const resumeId = this.pickerMap.get(value);  // Property 'pickerMap' does not exist on type 'Vue'.
      this.$emit('confirm', resumeId);
    },
  },
});
</script>

What is expected?

I don't know if it's because of my writing, or because of the configuration that caused me this error. I wrote the code based on the official document. I believe it can be build successfully.

What is actually happening?

When I run npm run build, an error Property 'pickerMap' does not exist on type 'Vue'. The complete prompt is as follows:

ERROR in E:/project/demo/src/components/picker.vue
44:29 Property 'pickerMap' does not exist on type 'Vue'.
     42 | methods: {
     43 | onConfirm(value: string): void {
   > 44 | const resumeId = this.pickerMap.get(value);
        | ^
     45 | this.$emit('confirm', resumeId);
     46 | },
     47 | },

I do not know of any reason for this error. It is imperative that I have a friend to help me solve this error, but I hope that the official can speed up the improvement of TypeScript's documentation, because I believe TypeScript will become popular. Thank you.

@sodatea
Copy link
Member

sodatea commented Jun 25, 2018

Duplicate of #6841

😕
I think we need to address this issue in the docs if 2.6 isn't going to be released any time soon.

@sodatea sodatea closed this as completed Jun 25, 2018
@weihongyu12
Copy link
Author

Official documentation is really too little for TypeScript

@waterVenice7
Copy link

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
    }
  }
})

@miking-the-viking
Copy link

The trick is that it is TypeScript, you'll need to define an interface that your component implements. This is the blessing and curse of Statically Types languages. Take for instance this example with my Nav component in Vue:

<template lang="pug">
nav.navbar(role="navigation" aria-label="main navigation")
    <!-- Branding and Hamburger -->
    .navbar-brand
        a.navbar-item(href="https://bulma.io")
            img(src="https://bulma.io/images/bulma-logo.png" alt="Bulma: a modern CSS framework based on Flexbox" width="112" height="28")
        a.navbar-burger(role="button" aria-label="menu" aria-expanded="false")
            span(aria-hidden="true")
            span(aria-hidden="true")
            span(aria-hidden="true")
    <!-- Navbar Menu -->
    <!-- Hidden on mobile, needs .is-active added at those sizes -->
    div(v-bind:class="{navBarMenuClass}")
        
</template>

<script lang="ts">

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

const navbarMenuBaseClass = 'navbar-menu';

interface INav {
    menuIsActive: boolean;
}

@Component
export default class Nav extends Vue implements INav  {
    menuIsActive: boolean = false;
    
    computed() {
        return {
            navbarMenuClass: navbarMenuBaseClass + (this.menuIsActive ? 'is-active' : '')
        }
    }
}
</script>

Until I added the implemements INav and the INav interface definition, I was getting type errors for this.menuIsActive.

@AndreyBulezyuk
Copy link

var VueApp: any = Vue;

That helped. Thanks.

But that is not a valid and scalable solution, if you have tons of components...

$router, $store, etc. are being injected into Vue Type in main.js with new Vue({...}). TypeScript cannot know that they are present in 'this'/Vue, because Vue Interface in vue.d.ts does not cover these keys. I think the Vue Interface in vue.d.ts should have optional parameters for those plugins(vuex, vue-router), so TS knows that they ($store, $router) could be present.

@jerradpatch
Copy link

jerradpatch commented Jan 21, 2020

I opened the vue.d.ts and seen this

 extend<Data, Methods, Computed, PropNames extends string = never>(options?: ThisTypedComponentOptionsWithArrayProps<V, Data, Methods, Computed, PropNames>): ExtendedVue<V, Data, Methods, Computed, Record<PropNames, any>>;

this solved my issue
Vue.extend<any, any, any, any>({

@mediafreakch
Copy link

mediafreakch commented Feb 26, 2020

You can type Data, Methods, Computed and Props like this:

interface Props {
  columns: string[]
  show: boolean
}

interface Data {
  isVisible: boolean
}

interface Computed {
  pickerList: string[]
  pickerMap: Map<string, number>
}

interface Methods {
  onConfirm: (value: string) => void
}

export default Vue.extend<Data, Methods, Computed, Props>({
  methods: { ... },
  data() { ... },
  computed: { ... },
  props: { ... },
  render() { ... }
})

This way the Typescript errors should go away.
Note that for the example above to work, you need to have props defined as an object, not in the props: [] syntax. For the latter, the type definition needs to be different.

@Ettapp
Copy link

Ettapp commented Feb 25, 2021

TypeScript can understand most of those types on it's own, but even if it is not used where the error is shown, all the computed methods and the render method should be typed !

I just spent hours to find out that if I simply put any as my computed methods return type (which I don't recommand, it's just to show the result), the errors about Property [my-data] does not exist on type 'Vue' disapear !

It's writen here: https://vuejs.org/v2/guide/typescript.html#Annotating-Return-Types

@MMN3003
Copy link

MMN3003 commented Aug 7, 2021

I fix this by using defineComponent

my code was like this

<template>
  <div class="about" v-if="seen">
  </div>
  <div class="about">
    <ol>
      <li v-for="todo in todos" :key="todo.text">
        {{ todo.text }}
      </li>
    </ol>
  </div>
   <p>{{ message }}</p>
  <button v-on:click="reverseMessage">Reverse Message</button>
   <p>{{ message }}</p>
  <input v-model="message">
</template>

<script lang="ts">
export default {
  data(): { seen: boolean; message: string; todos: { text: string; }[]; } {
    return {
      seen:false,
      message:'asdas asdsdas',
      todos: [
        { text: "Learn JavaScript" },
        { text: "Learn Vue" },
        { text: "Build something awesome" },
      ],
    };
  },
  methods: {
    reverseMessage():void {
      console.log(this);
      this.message = this.message.split('').reverse().join('');
    }
  }
};
</script>

and I have error "property message does not exist on type..."

then I fix it with

<template>
  <div class="about" v-if="seen">
  </div>
  <div class="about">
    <ol>
      <li v-for="todo in todos" :key="todo.text">
        {{ todo.text }}
      </li>
    </ol>
  </div>
   <p>{{ message }}</p>
  <button v-on:click="reverseMessage">Reverse Message</button>
   <p>{{ message }}</p>
  <input v-model="message">
</template>

<script lang="ts">
import { defineComponent } from 'vue';
export default  defineComponent({
  data(): { seen: boolean; message: string; todos: { text: string; }[]; } {
    return {
      seen:false,
      message:'asdas asdsdas',
      todos: [
        { text: "Learn JavaScript" },
        { text: "Learn Vue" },
        { text: "Build something awesome" },
      ],
    };
  },
  methods: {
    reverseMessage():void {
      console.log(this);
      this.message = this.message.split('').reverse().join('');
    }
  }
});

</script>

errors gone and work fine :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants