本文参考 Vue3.0 文档
TypeScript with Composition API
模块。
本文假定用户使用场景是
<script setup>
与
组合式 API
,代码都跑写在
<script setup lang="ts">
。所以文内大部分代码块里的代码会省略掉
<script setup lang="ts">
这部分且不考虑
选项式 API
的情况。
props
props
的类型声明分为以下两种
运行时声明(自动推导)
基于类型的声明(泛型)
两种方式编译以后得到的 “运行时的 props ”是一致的(即选项式API 里的
props
),以上两种都可以使用,但不能同时使用两种。
运行时声明(自动推导)
在定义组件内
props
时,
defineProps
方法支持从它的参数自动推导类型
const props = defineProps({
year: { type: Number, required: true },
month: Number,
day: Number
基于类型的声明(泛型)
注意: 泛型参数可以包含从其他文件引入的类型,但它本身不能是一个直接导入的类型
泛型形式无法定义默认值, 需要开启实验性功能里的 响应式解构 props 才能设定默认值
也可以给 defineProps
传递定义好的对象类型或接口
const props = defineProps<{
year: number,
month?: number,
day?: number
interface Props {
year: number,
month?: number,
day?: number
const props = defineProps<Props>()
const { year, month = 1, day = 1 } = defineProps<Props>()
emit
类型定义方式与 props
一致,也是分为 “运行时”、“基于类型”两种方式
运行时声明(自动推导)
const emit = defineEmits(['update'])
基于类型的声明(泛型)
interface Emit {
(e: "update", id: number): void;
const emit = defineEmits<Emit>();
emit("update", 1)
ref
类型标注共有三种方式
import { Ref, ref } from 'vue';
let year = ref(2022); // Ref<number>
let yearEmpty = ref(); // Ref<any>
import { ref, Ref } from 'vue';
let month: Ref<number | string> = ref('10'); // Ref<string | number>
import { ref } from 'vue';
let day = ref<number>(10);
let dayEmpty = ref<number>();
reactive
reactive
类型标注和 ref
一样,共有三种方式
泛型(不推荐使用)
import { reactive } from 'vue';
const tom = reactive({ name: 'Tom' });
const tomEmpty = reactive({});
import { reactive, ref } from 'vue';
interface Dog { name: string }
const spike: Dog = reactive({ name: 'Spike' })
const spikeDeepRef: Dog = reactive({ name: ref('Spike') })
泛型(不推荐使用)
官方文档: 不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。
import { reactive, ref } from 'vue';
interface Mouse { name: string }
const mouse = reactive<Mouse>({ name: "jerry" })
const mouseDeepRef = reactive<Mouse>({ name: ref('jerry') })
computed
computed
共有三种方式
类型注解( 不推荐使用, 官方文档也未标出 )
import { computed, ComputedRef, ref } from 'vue';
const num = ref(10);
const double = computed(() => num.value * 2)
import { computed, ref } from 'vue';
const num = ref(10);
const three = computed<number>(() => num.value * 3)
类型注解 (不推荐使用)
官方文档: 不推荐使用 reactive() 的泛型参数,因为处理了深层次 ref 解包的返回值与泛型参数的类型不同。
import { computed, ComputedRef, ref } from 'vue';
const num = ref(10);
const four: ComputedRef<number> = computed(() => num.value * 4)
const fourError: number = computed(() => num.value * 4)
provide
provide
比较特殊,他是无法做到自动推导的,想要让 provide
提供的值被注入时能被准确的标注类型,只能使用 Vue
提供的 InjectionKey
接口, 它是一个继承自 Symbol 的泛型类型。
未使用 InjectionKey
import { provide } from "vue";
let tom = { name: "tom" };
provide("cat", tom);
import { inject } from "vue";
const tom = inject("cat");
const tomCorrect = inject<{ name: 'string' }>("cat")
const tomError = inject<string>("cat")
使用 InjectionKey
import { InjectionKey } from "vue";
export const cat = Symbol() as InjectionKey<{ name: string }>;
import { cat } from "./keys.ts";
import { provide } from "vue";
let tom = { name: "tom" };
provide(cat, tom);
import { inject } from "vue";
import { cat } from "./keys.ts";
const tom = inject(cat);
看完代码会发现,以上代码块里,能识别出类型的都会带着 undefined
类型,要去除掉它的话,只需要在注入方传递默认值或类型断言
import { provide } from "vue";
let tom = { name: "tom" };
provide("cat", tom);
import { inject } from "vue";
const tom = inject("cat") as { name: string; };
const tomWithDefaultVal = inject<{ name: string }>("cat", { name: "tom" });
event
原生的事件对象类型会被标注为 any
,需要使用 Event
来显式的标注它的类型。且需要显式地强制转换 event
上的 property
<script setup lang="ts">
function handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value)
</script>
<template>
<input type="text" @change="handleChange" />
</template>
模板 ref
模板 ref 需要通过一个显式指定的泛型参数和一个初始值 null 来创建
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const el = ref<HTMLInputElement | null>(null)
onMounted(() => {
el.value?.focus()
</script>
<template>
<input ref="el" />
</template>
组件模板 ref
首先需要通过 typeof
得到其类型,再使用 TypeScript
内置的 InstanceType
工具类型
import MyModal from './MyModal.vue'
const modal = ref<InstanceType<typeof MyModal> | null>(null)
const openModal = () => {
modal.value?.open()
</script>
复制代码