前言
在开发vue3的过程中,总会有那么一些方法忘记了怎么去写ts的类型注解,所以稍微整理一下vue中使用到的ts类型注解。另外本文章只考虑composition API
也就是组合式API。
ref
一般情况下
// 推导出来的类型: Ref<number>
const num = ref(888)
当给定一个初始值的时候,ref会自动推导它的类型,当没有赋值的时候ref()
,类型则是any
泛型参数
// 推导出来的类型: Ref<number | string>
const year = ref<number | string>(2023)
year.value = '2023' // ok
当指定了泛型参数,但是没有给定初始值ref<number>()
的时候,那么得到的将是一个包含undefined
的联合类型:
// 推导出来的类型: Ref<number | undefined>
const num = ref<number>()
也可以传入一个比较复杂的类型
interface List {
id: number,
title: string,
content: string
}
// 推导出来的类型: Ref<List | undefined>
const list = ref<List>()
reactive
一般情况下
// 推导得到的类型:{ title: string }
const book = reactive({ title: '标题' })
指定类型
interface Book {
title: string
year?: number
}
const book: Book = reactive({ title: '标题' })
不推荐使用泛型参数,因为处理深层次ref解包的返回值和泛型参数的类型不同
上面这句是什么意思呢?为什么reactive()
不推荐使用泛型来指定类型呢?举个例子:
interface Book {
title: string
year?: number
}
const book = reactive<Book>({ title: '标题' })
这样是没有问题的,但是如果reactive
中有使用ref
类型的话,例如以下情况:
interface Book {
title: string
year?: number
}
const title = ref("我是标题")
// 报错:Type 'Ref<string>' is not assignable to type 'string'.
const book = reactive<Book>({ title: title })
那如果把title的类型定义成Ref<string>
呢?如:
interface Book {
title: Ref<string>
year?: number
}
const title = ref("我是标题")
const book = reactive<Book>({ title: title })
但你会发现,book
的类型会变成
const book: {
title: string;
year?: number;
}
title
的类型是string
并不是定义的Ref<string>
,所以reactive带有深层次的ref
的时候,如果通过泛型来约束类型,类型会对应不上的。
computed
computed
和ref
一样都是通过泛型来指定类型,如果不指定类型那么会自动推导类型
const double = computed<number>(() => {
// 若返回值不是 number 类型则会报错
})
defineProps
运行时声明
const props = defineProps({
id: {type: Number, required: true},
title: String
})
props.id // number
props.title // string | undefined
运行时声明就是沿用js的那一套,然而通过泛型参数来定义props的类型通常更加直接:
const props = defineProps<{
id: number,
title?: string
}>()
需要注意的是:在 3.2 及以下版本中,
defineProps()
的泛型类型参数仅限于类型文字或对本地接口的引用。 这个限制在 3.3 中得到了解决。最新版本的 Vue 支持在类型参数位置引用导入和有限的复杂类型。但是,由于类型到运行时转换仍然基于 AST,一些需要实际类型分析的复杂类型,例如条件类型,还未支持。您可以使用条件类型来指定单个 prop 的类型,但不能用于整个 props 对象的类型。
不过我们发现一个问题,怎么定义它的默认值呢?使用withDefaults
来定义默认值
interface Props {
id: number,
title?: string
}
const props = withDefaults(
defineProps<Props>(), {
id: 1,
title: "我是标题"
})
defineEmits
在 <script setup>
中,emit
函数的类型标注也可以通过运行时声明或是类型声明进行:
<script setup lang="ts">
// 运行时
const emit = defineEmits(['change', 'update'])
// 基于类型
const emit = defineEmits<{
(e: 'change', id: number): void
(e: 'update', value: string): void
}>()
// 3.3+: 可选的、更简洁的语法
const emit = defineEmits<{
change: [id: number]
update: [value: string]
}>()
</script>