5

I've been working with Vue for a bit now but have started moving to implementations with Typescript. I'm running into an issue where I'm not able to access the child's methods via the refs on the parent.

Parent Code:

<template>
  <ref-test ref="child"/>
</template>

<script lang="ts">
import Vue from "vue";
import RefTest from "./RefTest.vue";

export default Vue.extend({
  name: "RefParent",
  components: {
    RefTest
  },
  data: () => ({}),
  methods: {},
  mounted() {
    const child = this.$refs.child as RefTest;
    child.pingMe();
  }
});
</script>

<style scoped></style>

Child Code:

<template>
  <div>REF TEST...</div>
</template>

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

export default Vue.extend({
  name: "RefTest",
  data: () => ({}),
  methods: {
    pingMe() {
      console.log("refTest pingMe");
    }
  }
});
</script>

<style scoped></style>

The issue I'm seeing is that in the parent when I reference the child with const child = this.$refs.child as RefTest; I'm seeing the error: 'RefTest' refers to a value, but is being used as a type here.. In addition, the child.pingMe(); is reporting: Property 'pingMe' does not exist on type 'Vue'.

I've tried various work arounds found here: https://github.com/vuejs/vue/issues/8406 primarily around the inferface definitions and the Vue.extend<> call.

I appreciate any help with helping me continue to wrap my brain around the differences with using Typescript.

2
  • The error says what's wrong. RefTest is neither a type nor an interface, so it cannot be used where a type is expected. Try as typeof RefTest. Commented Apr 29, 2020 at 16:46
  • Thanks. I guess being newer to Typescript I'm not understanding the errors? Using as typeof RefTest gives new errors. TS2352: Conversion of type 'Vue | Element | Vue[] | Element[]' to type 'VueConstructor<Vue>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.   Type 'Element[]' is missing the following properties from type 'VueConstructor<Vue>': extend, nextTick, set, delete, and 8 more. Commented Apr 29, 2020 at 17:05

3 Answers 3

7

Ok. Did some more experimenting and I'm not sure this is the 'right' solution or most elegant but the code works and the compiler isn't complaining. Ultimately I created an interface type that contains the method I'm trying to reach. In the parent I now cast the $ref as that interface type and all appears to be well. Please let me know if there is a better more elegant way of doing this (or if this is the 'best' way) Please see full code below.

Interface (types/refInterface.ts):

import Vue from "vue";

export interface RefInterface extends Vue {
  pingMe(): void;
}

Parent:

<template>
  <ref-test ref="child" />
</template>

<script lang="ts">
import Vue from "vue";
import RefTest from "./RefTest.vue";
import { RefInterface } from "@/types/refInterface";

export default Vue.extend({
  name: "RefParent",
  components: {
    RefTest
  },
  data: () => ({}),
  methods: {},
  mounted() {
    const child = this.$refs.child as RefInterface;
    child.pingMe();
  }
});
</script>

<style scoped></style>

The 'child' code did not change for this to work so did not re-paste it.

Sign up to request clarification or add additional context in comments.

Comments

2

This is how you do it in Vue3 + Typescript

const myEditor = ref<InstanceType<typeof MyEditor>>()
myEditor.value?.flushEvents()

source: https://github.com/vuejs/composition-api/issues/402

1 Comment

Thanks. I'll have to give this a shot. Seems cleaner than my current solution.
2

I know this is an old question but came accross it and want to offer my solution in case someone does not want to have to create an interface everytime you call a single method on a ref:

mounted() {
  const child = this.$refs.child as Vue & { pingMe: () => void };
  child.pingMe();
}

1 Comment

This looks pretty clean too and I appreciate the continued options being provided. I'll have to give this a shot soon. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.