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

vm arg in next callback in beforeRouteEnter isn't typed to the component #701

Open
rudnik275 opened this issue Jan 8, 2021 · 11 comments
Open
Labels
contribution welcome The team would welcome a contribution from the community for this issue typescript Problem related to TS typings

Comments

@rudnik275
Copy link

Version

4.0.2

Reproduction link

https://codesandbox.io/s/competent-architecture-4ezib?file=/src/App.vue

Steps to reproduce

import {defineComponent, ref} from 'vue'

export default defineComponent({
beforeRouteEnter(to, from, next) {
  next(vm => {
    vm.customVariable = 'changed text'
       ^^^  TS2339: Property 'customVariable' does not exist on type 'ComponentPublicInstance{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase >'.
  })
},

setup() {
  const customVariable = ref('')
  return {
    customVariable
  }
}
})

What is expected?

returns correct instance variables

What is actually happening?

Property 'customVariable' does not exist on type 'ComponentPublicInstance{}, {}, {}, {}, {}, {}, {}, {}, false, ComponentOptionsBase >'.

@posva posva added the typescript Problem related to TS typings label Jan 8, 2021
@posva posva changed the title NavigationGuard doesn't provide current instance variables vm arg in next callback in beforeRouteEnter isn't typed to the component Jan 8, 2021
@posva posva added the contribution welcome The team would welcome a contribution from the community for this issue label Jan 11, 2021
@posva
Copy link
Member

posva commented Jan 12, 2021

As a note: I'm unsure of the feasibility of this one but if someone figures out how to type it, please file a PR!

@tinobino
Copy link

tinobino commented Mar 18, 2021

For the time being using vue-class-component can help here.
For instance with having a class-style Vue component named "Main" you can just do the following:

next(vm => {
   const main = vm as Main;
   main.customVariable = 'changed text';
});

It still feels like a hack but it works at least.

@tinobino
Copy link

Please see also my comment here.

@notdp
Copy link

notdp commented Apr 9, 2021

I met same problem today,and I solved problem.
actually,according to my console log,vm has property customVariable.
so this problem same like caused by typescript type.

vm.customVariable = 'changed text'
change to:
(vm as any).customVariable = 'changed text'
It worked for me.

there is my code.

import {defineComponent} from 'vue';
import baseurl from "@/api/baseurl";

const axios = require('axios').default;

export default defineComponent({
  name: 'ProductPage',
  data() {
    const product = {
      id: 0,
      name: '',
      type: '',
      description: '',
      saleUserid: -1,
      salePrice: 0,
      picUrl: ''
    }
    return {
      product,
    };
  },
  props: ['id'],
  beforeRouteEnter(to, from, next) {
    axios.get(baseurl.getProducts + '/' + to.params.id)
        .then((response: any) => {
          next(vm => {
            // console.log(vm)
            // console.log((vm as any).product)
            (vm as any).product = response.data;
          })
          console.log(response);
        })
        .catch(function (error: any) {
          console.log("GET PRODUCT ERROR!!!")
          console.log(error);
        });
  }

});

@rw-esc
Copy link

rw-esc commented Oct 22, 2022

Another option would be to assign the component to a variable and then use vm as InstanceType<typeof Component> e.g.:

import axios from "axios";
import {defineComponent} from "vue";

const Component = defineComponent({

    async beforeRouteEnter(to, from, next) {
        const data = (await axios.get("/products/" + to.params.id)).data;
        next(vm => {
            (vm as InstanceType<typeof Component>).product = data;
        });
    },

    data() {
        return {
            product: {},
        };
    }
});

export default Component;

@Akryum
Copy link
Member

Akryum commented Jul 27, 2023

You can import the module from itself:

<script lang="ts" setup>
// in MyComp.vue
import type Self from './MyComp.vue'

const foo = 'bar'

defineExpose({
  foo,
})

defineOptions({
  beforeRouteEnter: (to, from, next) => {
    next(async (vm: InstanceType<typeof Self>) => {
      vm.foo // string
    })
  },
})
</script>

@posva NavigationGuard is missing a generic to be able to pass the type of vm in next

@Akryum
Copy link
Member

Akryum commented Jul 27, 2023

@posva Also the typing seems to be off as the type of the current component is not compatible with the signatures of next:
image

@posva
Copy link
Member

posva commented Jul 27, 2023

I don't know where InstanceType comes from. It doesn't come from vue-router but I imagine it should be assignable to ComponentPublicInstance in order for it to work.

NavigationGuard doesn't really need a generic as long as you can specify a more concrete type of component instance. BTW beforeRouteEnter is of type NavigationGuardWithThis, not NavigationGuard

@Akryum
Copy link
Member

Akryum commented Jul 27, 2023

https://www.typescriptlang.org/docs/handbook/utility-types.html#instancetypetype

@Akryum
Copy link
Member

Akryum commented Jul 27, 2023

BTW beforeRouteEnter is of type NavigationGuardWithThis

You are sure? I though there is no this in beforeRouteEnter

Copy link
Member

posva commented Jul 27, 2023

Yes, because it has the this explicitly set to undefined 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contribution welcome The team would welcome a contribution from the community for this issue typescript Problem related to TS typings
Projects
None yet
Development

No branches or pull requests

6 participants