下面这种情况可以成功编译的。
<script setup lang="ts">
interface IProps {/* 一些类型定义*/}
const props = defineProps<IProps>();
</script>
1
2
3
4
2
3
4
但如果将类型定义抽取出来则会报错编译失败。
<script setup lang="ts">
import {IProps} from './types'
const props = defineProps<IProps>();
</script>
1
2
3
4
2
3
4
因为Vue SFC组件仅编译组件所在文件,无法分析到外部引入的类型定义。
关于该问题的讨论可以参考:issue (opens new window)。
终于在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 >;
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
说明:
- 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 >;
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
至此status的类型推导变成必选的了。
总结
- 类型声明方式定义 defineProps 目前仅支持将props类型定义到组件所在文件中
- 运行时声明方式定义 defineProps 体验较好些,但需要配合 PropType 和 ExtractPropTypes 使用
如果不需要将props类型抽取出来,则两种方式都可以。