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

Property 'xxx' does not exist on type CombinedVueInstance ? #8721

Open
SunshowerC opened this issue Aug 28, 2018 · 56 comments
Open

Property 'xxx' does not exist on type CombinedVueInstance ? #8721

SunshowerC opened this issue Aug 28, 2018 · 56 comments

Comments

@SunshowerC
Copy link

SunshowerC commented Aug 28, 2018

Version

2.5.17

Reproduction link

Steps to reproduce

  1. use vue-cli init a ts hello-world project .
  2. code like that
<script lang="ts">
import Vue from "vue";
export default Vue.extend({
  name: "HelloWorld",
  props: {
    msg: String
  },
  data():any {
    return {
      wtf: this.initData(), // throw ts error : Property 'initData' does not exist on type 'CombinedVueInstance<Vue, {}, {}, {}, Readonly<{ msg: string; }>>'.
    }
  },
 
  methods: {
    initData():any {
        return {
          a: ''
        }
    },
  },
 
});
</script>

What is expected?

How can i fix it ?

What is actually happening?

Property 'initData' does not exist on type 'CombinedVueInstance<Vue, {}, {}, {}, Readonly<{ msg: string; }>>'.

@SunshowerC SunshowerC changed the title Property 'xxx' does not exist on type CombinedVueInstance Property 'xxx' does not exist on type CombinedVueInstance ? Aug 28, 2018
@KaelWD
Copy link
Contributor

KaelWD commented Aug 28, 2018

It seems to be intentional, I guess so you can't accidentally access computed properties via a method?

type DataDef<Data, Props, V> = Data | ((this: Readonly<Props> & V) => Data)

edit: 540a38f, #5887 (comment)

@SunshowerC
Copy link
Author

I don't understand. What bad would happen if i access computed properties via a method ?

@KaelWD
Copy link
Contributor

KaelWD commented Aug 29, 2018

They don't exist yet: https://codepen.io/kaelwd/pen/pOErZw?editors=0011

@SunshowerC
Copy link
Author

Uh... I didn't use computed property, just use a method function, and the methods does exist in data.

image

And I may turn to vue-class-component instead of Vue.extend, the native vue is still not so friendly to typescript (Maybe just because i am not so proficient in vue). Anyway, thanks for helping me.

@KaelWD
Copy link
Contributor

KaelWD commented Aug 29, 2018

Yeah I know, it is a bit silly. Just a guess as to why they might've done that.

@zhuscat
Copy link

zhuscat commented Sep 3, 2018

Same here.

"vue": "^2.5.17"

"typescript": "^3.0.0"

Is there any way to access methods in data function?

@brandoncash
Copy link

Since this appears to be only a typing issue and not a runtime issue, there is an (ugly?) workaround available: cast this as type any:

return {
  wtf: (this as any).initData(),
};

Additionally omit the () to store a reference to the method that is executable outside of the current scope, e.g. if you pass it to a child via a prop.

@mms-
Copy link

mms- commented Oct 20, 2018

Same here. Vue 2.5 has better type declaration support for TypeScript but this seems broken.

@gcollombet
Copy link

Same problem for me

@ktsn
Copy link
Member

ktsn commented Nov 13, 2018

I guess we should remove this type from data option function and make it as the same as other function this type. The use case that OP provides looks totally valid.

I also faced another use case which I need comprehensive this type in data function when writing some function in it.

data() {
  return {
    someFunc: () => {
      this.someComputed() // `this` type here should be comprehensive
    }
  }
}

As a similar case, this type of beforeCreate seems also to be removed.

But they probably breaks existing apps type checking as we need to explicitly declare data function return type since it no longer infers return type of data due to this restriction. I'm not sure how much the change affects the existing apps...

nextprops added a commit to nextprops/vue-typescript-tsx that referenced this issue Dec 12, 2018
@nextprops

This comment has been minimized.

@JoshZA

This comment has been minimized.

@schnetzi
Copy link

Since this appears to be only a typing issue and not a runtime issue, there is an (ugly?) workaround available: cast this as type any:

return {
  wtf: (this as any).initData(),
};

Additionally omit the () to store a reference to the method that is executable outside of the current scope, e.g. if you pass it to a child via a prop.

So is this the proposed solution at the moment?

@danjohnso
Copy link

danjohnso commented Oct 17, 2019

One workaround I had been using is to add an Interface for the Vue instance like this:

interface IComponent {
    $refs: {
        Form: HTMLFormElement;
    };
    InitData(): void;
}

export default (Vue as VueConstructor<IComponent>).extend({
...

This will let you add typing for methods and $refs, does not seem to be any side effects.

EDIT:

I will add this too since I struggled to work with the types for nullable properties (late initialization) with Vue.extend. if you try to return a type | null that is initialized as null, the typings think its literally null and that it cannot be the type. Workaround is to cast the return again, which is annoying so I made a wrapper type. This works well if you have data that needs to be set in mounted, or is a component level data that maybe doesn't get initialized until a certain method is called (Form validator and Dialog reference in UI framework in my cases:

export type Nullable<T> = T | null;

Vue.extend({
    data() {
         const dialog: Nullable<Dialog> = null;

        return {
            dialog: dialog as Nullable<Dialog>
        };
    },
    methods: {
        ButtonClick(): void {
            this.dialog = new Dialog({});
        }
    }
});

@JaidenDeChon
Copy link

JaidenDeChon commented Oct 23, 2019

EDIT: See @IAMtheIAM's answer below

I had this error while working inside of a computed property. My data and computed were organized like this:

export default Vue.extend({
    name: 'componentName',
    data() {
        return {
            myDataPoint: false,
        };
    },
    computed: {
        trueOrFalse() {
            return this.myDataPoint ? 'is-true' : 'is-false';
        }
    },
})

It would give me the same error (Property myDataPoint does not exist on type CombinedVueInstance...)

However, when I declared what type would be returned by the function, the error went away:
(look to the trueOrFalse computed property for the change)

export default Vue.extend({
    name: 'componentName',
    data() {
        return {
            myDataPoint: false,
        };
    },
    computed: {
        // declare the type returned by your function/computed/method
        trueOrFalse(): string {
            return this.myDataPoint ? 'is-true' : 'is-false';
        }
    },
})

Hope this helps!

@douglas-pires
Copy link

Declare the return type worked for me as well... But such strange behavior.

@stoically
Copy link

stoically commented Nov 11, 2019

FWIW, the error shows for me only in VSCode, but when compiling with tsc directly, there's no error. Also, when I edit one of the falsely highlighted properties (like deleting one char and putting it back), most of the time the error just goes away.

@jacekkarczmarczyk
Copy link

@stoically microsoft/TypeScript#34999?

@tenadolanter
Copy link

tenadolanter commented Nov 14, 2019

Declare the return type worked for me sometimes, but turn to vue-class-component instead of Vue.extend will work awalys!

@daveberning
Copy link

Declare the return type worked for me as well... But such strange behavior.

Same here. Odd behavior but it works nonetheless. I supposed having a return in TypeScript never hurts haha!

@IAMtheIAM
Copy link

IAMtheIAM commented Jan 15, 2020

This happens for all my methods and data properties. What's the solution?

UPDATE: Apparently, you have to annotate the return type for your computed methods, otherwise all your methods and data properties won't appear to typescript as if they are on the CombinedVueInstance. As soon as I did that, all errors went away regarding this.

krmax44 added a commit to krmax44/clef.ninja that referenced this issue Feb 8, 2020
@sceee
Copy link

sceee commented Feb 17, 2020

Thanks @IAMtheIAM, your hint solved it for me. I was having the issue with methods that called vuex actions - and I thought initially the error might be in the type resolution for the vuex actions somehow. But it turned out I had added another computed property in the component that did not have a return type set. Adding this one solved it for my case.

@tomturton
Copy link

I had this issue until I gave all my computed properties return types.
However, Jest unit tests continued to throw the same TypeScript error.

I had to alter my expectation to follow this pattern:

expect((wrapper.vm as any).subtotalFormatted).toBe('£1,234.56');

Yuk! I hope this can be resolved soon.

@DarkEye123
Copy link

DarkEye123 commented Apr 23, 2020

I have this issue - but 'computed' statement is nowhere in my dummy project. I'm using just 'methods'. Basically reproduction is the same as the original post at the top. I tried the solution with the type declaration, this didn't help me (ts 3.8.3)

@KaelWD
Copy link
Contributor

KaelWD commented Oct 23, 2020

InstanceType<typeof mixin> or use this mixins utility I made for Vuetify: https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/util/mixins.ts

Vue 3 has proper typings for mixins.

@JaidenDeChon
Copy link

InstanceType<typeof mixin> or use this mixins utility I made for Vuetify: https://github.com/vuetifyjs/vuetify/blob/master/packages/vuetify/src/util/mixins.ts

Vue 3 has proper typings for mixins.

@KaelWD Would you mind explaining how we'd use InstanceType<typeof mixin>?

@JaidenDeChon
Copy link

For those experiencing the same error thrown as a result of using mixins in Vue 2.x, I'm going to dump some information and the solutions I found in my research below.

Here's a helpful explanation of why you're having this problem:

This is because you’re importing Vue from ‘vue’ package, thus TypeScript doesn’t have a clue that somewhere else you added property $myGlobalProperty to it.

After researching and reading around online, the consensus everywhere (including this thread) seems to be that in order to get proper mixin typings without any complications or workarounds, you'll want to upgrade to Vue 3.

If that isn't an option for you right now, this answer is what helped us overcome it. We went with option 1 until we can discuss option 2, and it will do until we can find a less limiting solution.

Here are some other solutions I came across today:

@pikilon
Copy link

pikilon commented Dec 19, 2020

I really can't believe this nightmare for not using decorators,
Even using a lot of typescript (Vues as VueConstructor...), It doesn't infers the types at all, and you can't access computed properties between them.
This is such a downer.
Thank you for you help everyone

@seupedro
Copy link

seupedro commented Mar 22, 2021

+1 in 2021. 😅

TL:DR for anybody else coming from Google after hours of searching:

  • For those expecting a fix like me. Vue.js 2 development was stopped at end of 2020.
  • This issue is 3 years old. Yeah, it is.
  • If you don't want use any hack. Yours options are: Vue 3 or class-components.

Hope it helps

@Shuunen Shuunen mentioned this issue Apr 7, 2021
Shuunen added a commit to NiceOrg/timey that referenced this issue Apr 7, 2021
@baybal
Copy link

baybal commented Apr 14, 2021

+1 in 2021.

TL:DR for anybody else coming from Google after hours of searching:

  • For those expecting a fix like me. Vue.js 2 development was stopped at end of 2020.
  • This issue is 3 years old. Yeah, it is.
  • If you don't want use any hack. Yours options are: Vue 3 or class-components.

Hope it helps

It's still there in 3.0

@igolka97
Copy link

@baybal
It's still there in 3.0

You mean that there are still same problems of Vetur in Vue 3.0 like in Vue 2.0?

@baybal
Copy link

baybal commented Apr 15, 2021

@baybal
It's still there in 3.0

You mean that there are still same problems of Vetur in Vue 3.0 like in Vue 2.0?

Yes

@janwidmer
Copy link

janwidmer commented Jun 16, 2021

I am still experiencing the problems described in this ticket.. :-/

My Setup:

  • Vue 3.0.11
  • Typescript 4.3.x
  • Single File Components defined by using defineComponent
<template>
  <div>Hello World 2</div>
</template>

<script lang="ts">
<template>
  <div>Hello World 2</div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue';

interface IHelloWorldObject {
  helloWorld: string;
}

interface IGoodbyeWorldObject {
  goodByWorld: string;
}

interface IData {
  goodByWorld: string;
  goodByWorldObject: IGoodbyeWorldObject;
}

export default defineComponent({
  name: 'HelloWorld',
  props: {
    helloWorld: {
      type: String,
      default: 'hello world',
      validator(value: string): boolean {
        return [
          'hello-world',
          'hello world',
          'hello.world',
        ].includes(value);
      },
    },
    helloWorldObject: {
      type: Object as PropType<IHelloWorldObject>,
      required: true,
    },
  },
  data(): IData {
    return {
      goodByWorld: 'Good By World',
      goodByWorldObject: {
        goodByWorld: 'Good By World Object',
      }
    };
  },
  computed: {
    halloWorldExtended(): string {
      // Property this.helloWorldObject does not exist on type ComponentPublicInstance
      return `${this.helloWorldObject.helloWorld}!`;
    },
  },
  mounted () {
    // Property this.helloWorldObject does not exist on type ComponentPublicInstance
    console.log(this.helloWorldObject.helloWorld)
    // Property this.helloWorldObject does not exist on type ComponentPublicInstance
    console.log(this.helloWorld)
    console.log(this.goodByWorld)
    console.log(this.goodByWorldObject.goodByWorld)
  }
});
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

I typed all return types of methods in computed / data. Typescript still says, that props being used in a method in computed / lifecycle / methods do not exist..

Update

It turned out, that the problem was the way, how my prop validator is written:

  • validator(value: string) { => props not defined when using in computed / lifecycle methods
  • validator: (value: string) => { => props all working when using in computed / lifecycle methods

After I figured it out, I have found other tickets describing this issue:

@Shuo-Mr
Copy link

Shuo-Mr commented Jun 21, 2021

I'll have to create a interface method for each mixins i use ? Even imported from external libraries ?

It's not ideal, but it's the only way I got it to work.

My problem is the same. Through the computed of mixins, I can't find its declaration on the component.

So is there a better solution now?

@K-Schaeffer-LOG
Copy link

Adding a type to all computed properties fixed it here.

@tautvilas
Copy link

I had the same error after adding head() section to nuxt vue page. After adding return type :any to head, the error disappeared. Maybe this will be helpful to somebody.

head(): any {

@kassiansun
Copy link

I encountered this issue when trying to import non-ts component and use it inside ts component. Tried every fix and finally got it work by rewrite the imported component with ts. This might be useful for people migrating to ts.

@ghost
Copy link

ghost commented Nov 25, 2021

#8721 (comment)
works for me as well! Thanks!
Screenshot 2021-11-25 at 10 29 22
Screenshot 2021-11-25 at 10 30 05

@MrCube42
Copy link

I have a somehow related type error as soon as switching from 2.7.10 to 2.7.11:

In my case, the error Property 'getCompleteConfigs' does not exist on type 'CreateComponentPublicInstance... appears when calling methods defined via options API, e.g. this.myMethod(). I could workaround this in some cases by changing data() { ... to data: () =>. In this case, the type is correctly inferred. However, when I want to access the props in data and I need to change to data: (vm) => vm.myProp the inference is also broken.

The exact same problem appear in the IDE when using Volar (vuejs/language-tools#1996 (comment)).

@emosheeep
Copy link

emosheeep commented Dec 6, 2022

Maybe you haven't turned on the "strict": true in your tsconfig.json

This is my demo code

import { defineComponent } from 'vue';

export default defineComponent({
  data() {
    return {
      type: 1,
      haha: 1,
    };
  },
  methods: {
    hello() {

    },
    world() {
      this;
    },
  },
});

Before I turned on the "strict" config, I got this

image

After that I got

image

@MrCube42
Copy link

MrCube42 commented Dec 8, 2022

We can't turn on strict mode yet. However, we migrated to Vue 3 in the meantime. From our side this issue is not relevant anymore.

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

No branches or pull requests