最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Composition API 如何在 setup 中结合 TypeScript 编写强类型组件
时间:2026-08-25 12:08:48 编辑:袖梨 来源:一聚教程网
在 setup 中结合 TypeScript 编写强类型组件,核心是利用类型声明与响应式 API 泛型能力,实现 props、ref、reactive、emit、defineExpose 等全面类型约束,确保输入输出精准可控。
在 setup 中结合 TypeScript 编写强类型组件,核心是利用类型声明 + 响应式 API 的泛型能力,让变量、函数、props、事件等全部具备可推导、可约束、可检查的类型。关键不在“能不能写”,而在于“怎么写才真正发挥类型安全的价值”。
响应式数据:用泛型明确基础类型
ref 和 reactive 是最常用的响应式 API,它们都支持泛型,这是实现强类型的第一步。
-
ref:适合基础类型或需要 .value 显式访问的场景。直接传入泛型参数,比如
ref或('hello') ref。即使不写泛型,TypeScript 也能自动推导(如([1, 2, 3]) ref(42)→Ref),但显式声明更清晰、更防误改。 - reactive:用于对象或数组等引用类型。必须配合接口或类型别名使用,否则会丢失深层属性类型。例如:
interface User { id: number; name: string; email?: string }
const user = reactive<User>({ id: 1, name: 'Alice' })
</script>
不推荐直接 reactive({}) 后再赋值,那样会导致类型宽松甚至 any 化。
Props 类型:优先用基于类型的声明
Vue 3 推荐用泛型方式定义 props,比运行时声明更简洁、更类型安全。
- 直接内联泛型:
defineProps<{ title: string; count?: number }>() - 拆分为接口(更推荐):
interface Props {
title: string
disabled?: boolean
onConfirm: (id: string) => void
}
const props = defineProps<Props>()
这样不仅 props 有完整类型,连事件回调参数也受约束。
- 避免混用运行时声明(如
{ type: String })和泛型,除非要兼容某些动态校验逻辑;若必须用 PropType,记得导入:import type { PropType } from 'vue',然后写book: Object as PropType<Book>。
事件与 emit:用 defineEmits 约束触发签名
emit 不再是随意字符串,而是可被 IDE 提示、编译检查的函数调用。
- 简单事件:
const emit = defineEmits<{ (e: 'change', value: string): void; (e: 'submit'): void }>() - 配合接口更清晰:
type Emits = {
'update:modelValue': [value: string],
'error': [msg: string, code: number]
}
const emit = defineEmits<Emits>()
模板中触发
@click="emit('update:modelValue', 'new')",传参错误会在开发阶段报错。
组合逻辑与返回值:用 defineExpose 暴露可控类型
当父组件需调用子组件方法或读取内部状态时,defineExpose 是唯一安全出口。
- 默认 setup 不对外暴露任何内容。需主动声明:
const inputValue = ref('')
const validate = () => !!inputValue.value
defineExpose({ inputValue, validate })
- 暴露的内容会被类型推导,父组件通过
ref获取实例后,能获得完整类型提示,比如childRef.value.validate()返回 boolean,且参数不可乱传。
不复杂但容易忽略:类型不是越多越好,而是要在关键输入输出点(props / emit / expose / API 返回值)做精准约束。一次写对,后续所有调用都自动受益。