yaquawa
yaquawa

Reputation: 7338

How to type vue instance out of `defineComponent()` in vue 3?

As you know, as of Vue 3, component could be written in TypeScript:

/// modal.vue

<template>
  <div class="modal"></div>
</template>

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

export default defineComponent({
  name: "Modal",
  props: {
    foo: String,
    bar: String
  },
  mounted() {
    this.$props.foo // how to type `this` out of this context?
  }
});
</script>

My question is how can I type the vue instance out of the defineComponent function?

/// another ts file.
let modal:???; // what the `???` should be?

modal.$props.foo // infer `$props.foo` correctly

Upvotes: 11

Views: 11506

Answers (2)

wobsoriano
wobsoriano

Reputation: 13434

Use the TypeScript's built-in InstanceType utility to extract its instance type

import Modal from './modal.vue'

type ModalInstance = InstanceType<typeof Modal>

type Foo = ModalInstance['$props']['foo']

enter image description here

Another one using a utility type:

import { AllowedComponentProps, Component, defineComponent, VNodeProps } from 'vue'

export type ExtractComponentProps<TComponent> =
  TComponent extends new () => {
    $props: infer P;
  }
    ? Omit<P, keyof VNodeProps | keyof AllowedComponentProps>
    : never;
  
const TestComponent = defineComponent({
  props: {
    disabled: {
      type: Boolean,
    },
  },
});
  
type Props = ExtractComponentProps<typeof TestComponent>

// type Props = {
//   disabled?: boolean | undefined;
// }

Upvotes: 10

David Driscoll
David Driscoll

Reputation: 1419

The "simple" answer I was going to give was to use ReturnType<typeof defineComponent> however that doesn't carry any of the type information. As I started to look at how ReturnType could be used with a generic method I fell down stackoverflow rabbit hole where these seemed like something to explore

However after looking at it, vue has an exported type ComponentPublicInstance that can be used fairly easily. ComponentPublicInstance also has handful of different generic parameters.

import { ComponentPublicInstance } from 'vue';

let instance: ComponentPublicInstance<{ prop: string }, { value: string }>;

Upvotes: 9

Related Questions