第 20 章:TypeScript + Vue
学习目标
- 写 props / emit 的 TS 类型
- 用
defineProps<{}>配合默认值 - 用
defineModel简化 v-model - 避坑:模板 ref 的类型
一、组件 props 类型
vue
<script setup lang="ts">
defineProps<{
name: string
age?: number
tags?: string[]
user: { id: number; name: string }
}>()
</script>带默认值:
ts
withDefaults(
defineProps<{ name?: string; age?: number }>(),
{ name: '匿名', age: 18 },
)二、emit 类型
ts
const emit = defineEmits<{
(e: 'change', val: string): void
(e: 'update:modelValue', val: number): void
}>()Vue 3.3+ 简写:
ts
const emit = defineEmits<{
change: [val: string]
'update:modelValue': [val: number]
}>()三、defineModel(Vue 3.4+)
vue
<script setup lang="ts">
const model = defineModel<string>() // 默认 modelValue
const title = defineModel<string>('title') // 命名 model
</script>
<template>
<input v-model="model" />
<input v-model="title" />
</template>vue
<MyInput v-model="name" v-model:title="t" />四、模板 ref 类型
vue
<script setup lang="ts">
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
const inputRef = ref<HTMLInputElement | null>(null)
const compRef = ref<InstanceType<typeof MyComponent> | null>(null)
onMounted(() => {
inputRef.value?.focus()
compRef.value?.reset()
})
</script>
<template>
<input ref="inputRef" />
<MyComponent ref="compRef" />
</template>⚠️ 坑 1:模板 ref 默认为
any,Vue 3.5+ 才是Ref<unknown>,必须显式标注。
五、组件实例类型
ts
import MyComponent from './MyComponent.vue'
const ref1 = ref<InstanceType<typeof MyComponent> | null>(null)子组件用 defineExpose 暴露字段:
ts
// MyComponent.vue
defineExpose({ reset, count })六、泛型组件
vue
<script setup lang="ts" generic="T extends { id: string }">
defineProps<{ items: T[]; onSelect: (item: T) => void }>()
</script>vue
<Picker :items="users" :on-select="select" />⚠️ 坑 2:
generic是 Vue 3.3+ 特性,3.2 不支持。
七、reactive 对象类型
ts
import { reactive, ref } from 'vue'
interface User {
id: number
name: string
age?: number
}
const user = reactive<User>({ id: 1, name: 'A' })
const users = ref<User[]>([])八、Pinia store 类型
ts
export const useUserStore = defineStore('user', () => {
const name = ref('')
const token = ref('')
return { name, token }
})vue
const store = useUserStore()
store.name = 'A' // ✅ 类型推断💡
ref('')TS 自动推断成Ref<string>,不用标;只有初值是 null / 空数组 / 联合类型时才需要ref<Xxx>(...)。
九、工具类型
ts
import type { ComponentCustomProperties, Ref } from 'vue'
declare module 'vue' {
interface ComponentCustomProperties {
$api: typeof api
}
}ts
app.config.globalProperties.$api = api十、本章小结
| 能力 | 语法 |
|---|---|
| Props | defineProps<{}>() |
| Emits | defineEmits<{}>() |
| v-model | defineModel<T>() |
| Ref | ref<HTMLInputElement | null>(null) |
| 组件实例 | InstanceType<typeof X> |
动手练习
- 泛型列表:写
List<T>,接收items和render - defineModel:封装一个 number input v-model
- Ref 类型化:用 TS 拿组件实例,调用 expose 出的方法
下一章:第 21 章:组件库 →