vue icon indicating copy to clipboard operation
vue copied to clipboard

Property 'xxx' does not exist on type CombinedVueInstance ?

Open SunshowerC opened this issue 7 years ago • 56 comments
trafficstars

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 avatar Aug 28 '18 10:08 SunshowerC

It seems to be intentional, I guess so you can't accidentally access computed properties via a method? https://github.com/vuejs/vue/blob/3b43c81216c2e29bd519c447e930d6512b5782e8/types/options.d.ts#L34

edit: https://github.com/vuejs/vue/pull/6391/commits/540a38fb21adb7a7bc394c65e23e6cffb36cd867, https://github.com/vuejs/vue/pull/5887#discussion_r122128852

KaelWD avatar Aug 28 '18 10:08 KaelWD

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

SunshowerC avatar Aug 29 '18 08:08 SunshowerC

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

KaelWD avatar Aug 29 '18 08:08 KaelWD

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.

SunshowerC avatar Aug 29 '18 11:08 SunshowerC

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

KaelWD avatar Aug 29 '18 12:08 KaelWD

Same here.

"vue": "^2.5.17"

"typescript": "^3.0.0"

Is there any way to access methods in data function?

zhuscat avatar Sep 03 '18 13:09 zhuscat

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.

brandoncash avatar Oct 10 '18 16:10 brandoncash

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

mms- avatar Oct 20 '18 20:10 mms-

Same problem for me

gcollombet avatar Oct 22 '18 14:10 gcollombet

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...

ktsn avatar Nov 13 '18 03:11 ktsn

vue-tsx-support

nextprops avatar Jan 11 '19 10:01 nextprops

👍

JoshZA avatar Jan 18 '19 15:01 JoshZA

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?

schnetzi avatar Aug 20 '19 13:08 schnetzi

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({});
        }
    }
});

danjohnso avatar Oct 17 '19 13:10 danjohnso

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!

JaidenDeChon avatar Oct 23 '19 23:10 JaidenDeChon

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

douglas-pires avatar Nov 07 '19 22:11 douglas-pires

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.

stoically avatar Nov 11 '19 11:11 stoically

@stoically https://github.com/microsoft/TypeScript/issues/34999?

jacekkarczmarczyk avatar Nov 11 '19 11:11 jacekkarczmarczyk

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

tenadolanter avatar Nov 14 '19 02:11 tenadolanter

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!

daveberning avatar Nov 26 '19 14:11 daveberning

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.

IAMtheIAM avatar Jan 15 '20 22:01 IAMtheIAM

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.

sceee avatar Feb 17 '20 15:02 sceee

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.

tomturton avatar Mar 13 '20 10:03 tomturton

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)

DarkEye123 avatar Apr 23 '20 23:04 DarkEye123

Having the same issue when using the new Vue.js Composition API with vscode-insiders. The code compiles without TS errors but vscode shows an error nonetheless.

image

// setup(props, context) { 
watch(
    () => context.root.$q.screen.width,
    () => setMiniState(undefined)
)

Details Version: typescript 3.8.3, eslint 6.8.0

Version: 1.46.0-insider (system setup)
Commit: d487078dc7fc1c276657cadb61b4f63833a8df55
Date: 2020-05-07T16:19:54.327Z
Electron: 7.2.4
Chrome: 78.0.3904.130
Node.js: 12.8.1
V8: 7.8.279.23-electron.0
OS: Windows_NT x64 10.0.14393

Possible related issues: #23987, #29511 #32573 #34999

Type declaration didn't work here either as a workaorund. So this failed too in vscode:

watch(
   (): number => context.root.$q.screen.width,
   () => setMiniState(undefined)
)

DarkLite1 avatar May 08 '20 07:05 DarkLite1

I also have this problem in vscode

jQrgen avatar May 14 '20 15:05 jQrgen

Typescript 3.9 has made this even worse, I have to specify return types for methods too now.

KaelWD avatar May 29 '20 04:05 KaelWD

I'm very new to TypeScript. I tried all the advice here without any success, but I managed to build on @danjohnso's workaround to "solve" this with intersection types:

export default (Vue as VueConstructor<Vue & Interface1 & Interface2>).extend({

I have no idea if doing that is bad, but everything seems to work fine.

Edit: My issue is with properties from mixins not being recognized.

tipsy avatar Jun 06 '20 19:06 tipsy

Solution from @tipsy solved it for me. My use case was using mapState.

interface HomeMapState {
  plants: Plant[]
}

export default (Vue as VueConstructor<Vue & HomeMapState>).extend({
  name: 'Home',
  computed: {
    ...mapState<HomeState>('home', {
      plants: (state: HomeState) => state.plants,
    }),
    plantData(): Array<Plant | {}> {
      if (this.loading) {
        return new Array(5).fill({})
      }
      return this.plants
    },
  }
})

this.plants in plantData() was previously always yielding an error and couldn't be found on the Vue instance.

morkro avatar Jun 08 '20 07:06 morkro

I'm having this problem with Jest unit tests as well

taylorhoward92 avatar Jun 22 '20 21:06 taylorhoward92