如何在 vue 3 中从 `defineComponent()` 中键入 vue 实例?

yaq*_*awa 5 typescript vue.js

如您所知,从 Vue 3 开始,组件可以用 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>
Run Code Online (Sandbox Code Playgroud)

我的问题是如何从defineComponent函数中键入 vue 实例?

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

modal.$props.foo // infer `$props.foo` correctly
Run Code Online (Sandbox Code Playgroud)

wob*_*ano 10

使用 TypeScript 的内置InstanceType实用程序提取其实例类型

import Modal from './modal.vue'

type ModalInstance = InstanceType<typeof Modal>

type Foo = ModalInstance['$props']['foo']
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

另一种使用实用程序类型:

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;
// }
Run Code Online (Sandbox Code Playgroud)


Dav*_*oll 9

我要给出的“简单”答案是使用ReturnType<typeof defineComponent>但不携带任何类型信息的方法。当我开始研究如何ReturnType使用通用方法时,我掉进了stackoverflow 的兔子洞,这些似乎是值得探索的东西

然而看了之后,vue 有一个导出类型ComponentPublicInstance,可以相当容易地使用。 ComponentPublicInstance还有一些不同的通用参数。

import { ComponentPublicInstance } from 'vue';

let instance: ComponentPublicInstance<{ prop: string }, { value: string }>;
Run Code Online (Sandbox Code Playgroud)