3.4 KiB
3.4 KiB
Vue TypeScript 模式
Vue 3 开发的 TypeScript 专属模式。
Provide/Inject 类型
使用 InjectionKey 实现类型安全的依赖注入:
import type { InjectionKey } from 'vue'
import type { User } from './types'
// 定义类型化的 key
export const UserKey: InjectionKey<User> = Symbol('user')
// 提供者组件
const user = ref<User>({ id: 1, name: 'John' })
provide(UserKey, user)
// 消费者组件
const user = inject(UserKey) // Ref<User> | undefined
const user = inject(UserKey)! // Ref<User>(断言非空)
使用默认值:
const user = inject(UserKey, ref({ id: 0, name: 'Guest' }))
// 类型:Ref<User>(无 undefined)
vue-tsc 严格模板
启用更严格的模板类型检查:
# 以严格模式检查模板
vue-tsc --noEmit --strict-templates
可捕获如下模板错误:
- 访问不存在的属性
- 错误的 prop 类型
- 缺少必需的 props
tsconfig 设置
Vue 3 必需项:
{
"compilerOptions": {
"moduleResolution": "bundler",
"verbatimModuleSyntax": true,
"strict": true,
"jsx": "preserve"
}
}
moduleResolution: "bundler" - 与 Vite/webpack 的解析方式匹配。避免 .js 扩展名问题。
verbatimModuleSyntax: true - 强制使用显式 type 导入:
// ❌ 可能导致打包工具出现问题
import { User } from './types'
// ✅ 显式类型导入
import type { User } from './types'
组件类型辅助工具
从组件中提取 props 类型:
import type { ComponentProps, ComponentSlots, ComponentEmits } from 'vue-component-type-helpers'
import MyComponent from './MyComponent.vue'
type Props = ComponentProps<typeof MyComponent>
type Slots = ComponentSlots<typeof MyComponent>
type Emits = ComponentEmits<typeof MyComponent>
提取暴露的方法:
import type { ComponentExposed } from 'vue-component-type-helpers'
type Exposed = ComponentExposed<typeof MyComponent>
泛型组件
使用类型化的 slots 定义泛型组件:
<script setup lang="ts" generic="T extends { id: string }">
defineProps<{
items: T[]
}>()
defineSlots<{
default: (props: { item: T }) => any
}>()
</script>
<template>
<div v-for="item in items" :key="item.id">
<slot :item="item" />
</div>
</template>
Ref 类型收窄
正确处理 ref 类型收窄:
const maybeUser = ref<User | null>(null)
// ❌ TypeScript 仍然视为 User | null
if (maybeUser.value) {
maybeUser.value.name // 错误:可能为 null
}
// ✅ 使用 computed 或提取值
const userName = computed(() => maybeUser.value?.name ?? 'Guest')
// ✅ 或在同一表达式中守卫
maybeUser.value && maybeUser.value.name
事件处理器类型
正确为事件处理器添加类型:
// DOM 事件
const onClick = (e: MouseEvent) => { ... }
const onInput = (e: Event) => {
const target = e.target as HTMLInputElement
console.log(target.value)
}
// 组件 emits
const onUpdate = (value: string) => { ... }
常见错误
忘记显式导入类型:
// ❌ 运行时导入本应是纯类型的内容
import { User } from './types'
// ✅ 纯类型导入
import type { User } from './types'
未对字面量类型使用 as const:
// ❌ 类型为 string[]
const variants = ['primary', 'secondary']
// ✅ 类型为 readonly ['primary', 'secondary']
const variants = ['primary', 'secondary'] as const