Vue3解决definedProps无法引入外部Typescript类型定义

8,068 阅读2分钟

之前项目中使用到Typescript+Vue3,封装组件过程中发现definedProps无法使用外部引入的类型定义,因为时间关系当时没有仔细研究。

今天再次遇到此问题,于是花了些时间研究了一番:

下面这种情况可以成功编译的。

<script setup lang="ts">
interface IProps {/* 一些类型定义*/}
const props = defineProps<IProps>();
</script>

但如果将类型定义抽取出来则会报错编译失败。

<script setup lang="ts">
import {IProps} from './types'
const props = defineProps<IProps>();
</script>

因为Vue SFC组件仅编译组件所在文件,无法分析到外部引入的类型定义。

关于该问题的讨论可以参考:issue

之后找到一个vite库可以解决该问题:详情

本人测试不知道什么原因没有成功,于是另寻出路,终于在element plus源码中找到一个不错的解决方案。

element plus没有使用类型声明的方式定义props,而是使用传统的运行时声明方式定义props:

import type { PropType, ExtractPropTypes } from 'vue';
export const fooProps = {
  status: {
    type: String as PropType<'on' | 'off'>,
    required: true,
  },
};
​export type FooProps = ExtractPropTypes<typeof fooProps >;

说明:

  • status是字面量类型,需要使用vue提供的PropType支持

  • ExtractPropTypes作用是将props的类型定义抽取出来供外部使用

至此成功地将props的类型抽取出来了,但仍有一个小问题。

status的类型推导成可选的了,而我们需要是必选的,下面我们再修改一下:

import type { PropType, ExtractPropTypes } from 'vue';
export const fooProps = {
  status: {
    type: String as PropType<'on' | 'off'>,
    required: true,
    default: null,
  },
};
​export type FooProps = ExtractPropTypes<typeof fooProps >;

至此status的类型推导变成必选的了。

总结

  • 类型声明方式定义defineProps目前仅支持将props类型定义到组件所在文件中

  • 运行时声明方式定义defineProps体验较好些,但需要配合PropType和ExtractPropTypes使用’

如果不需要将props类型抽取出来,则两种方式都可以。