0Pricing
Vue Academy · 课时

使用 defineProps/defineEmits 定义带类型的 Props 与 Emits

泛型 defineProps ()、复杂类型、可选 props,以及事件触发的类型声明

使用 defineProps/defineEmits 定义带类型的 Props 与 Emits 是 CoddyKit 上的免费 Vue Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Vue Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Vue Academy 课程共包含 4 节课。

为组件输入和输出添加类型

使用 lang="ts" 后,defineProps 和 defineEmits 宏可以直接接受 TypeScript 类型。这样,组件流入和流出的数据就能在编译时得到检查。

从接口定义 Props

将类型传给 defineProps 泛型。使用接口可以让复杂的 props 结构更易读,也更容易复用。

<script setup lang="ts">
interface Props {
  title: string
  count: number
}
const props = defineProps<Props>()
</script>

内联类型字面量

对于小型组件,直接使用内联对象类型即可,不需要单独定义接口。

<script setup lang="ts">
const props = defineProps<{
  label: string
  disabled: boolean
}>()
</script>

使用 ? 定义可选属性

使用 ? 将属性标记为可选。可选 props 的类型是 T | undefined,父组件可以省略这些属性。

<script setup lang="ts">
interface Props {
  title: string
  subtitle?: string
}
const props = defineProps<Props>()
</script>

复杂的 Prop 类型

Props 可以是数组、联合类型或对象结构,也就是 TypeScript 能够表达的任何类型。

<script setup lang="ts">
interface Props {
  items: string[]
  size: 'sm' | 'md' | 'lg'
  user: { id: number; name: string }
}
const props = defineProps<Props>()
</script>

使用 withDefaults 设置默认值

仅包含类型的形式无法保存默认值,因此请将其包装在 withDefaults 中。第二个参数将 prop 名称映射到默认值。

<script setup lang="ts">
const props = withDefaults(defineProps<{
  size?: string
  count?: number
}>(), {
  size: 'md',
  count: 0
})
</script>

对象和数组的默认值

对象和数组的默认值必须从工厂函数中返回,就像选项式 API 中一样,以避免所有组件共享同一个实例。

withDefaults(defineProps<{
  tags?: string[]
}>(), {
  tags: () => []
})

声明带类型的 Emits

defineEmits 可以接受一种类型,其中以调用签名的形式列出每个事件及其负载。这可以在编译时捕获错误的负载类型。

<script setup lang="ts">
const emit = defineEmits<{
  (e: 'change', value: string): void
  (e: 'delete', id: number): void
}>()
</script>

发送带类型的负载

现在,emit 只接受有效的事件名称和匹配的负载类型。需要字符串却传入数字会导致编译错误。

function rename(name: string) {
  emit('change', name) // ok
  // emit('change', 123) // type error
}

命名元组语法

Vue 3.3+ 支持一种简写的对象形式,其中每个事件都映射到一个由其参数类型组成的元组,比调用签名更加简洁。

<script setup lang="ts">
const emit = defineEmits<{
  change: [value: string]
  delete: [id: number]
}>()
</script>

同时使用 Props 和 Emits

典型的带类型组件会同时声明两者:通过 defineProps 声明输入,通过 defineEmits 声明输出,并对整个数据流进行完整检查。

<script setup lang="ts">
defineProps<{ modelValue: string }>()
const emit = defineEmits<{
  'update:modelValue': [value: string]
}>()
</script>

快速检查

测试您对带类型 props 和 emits 的了解。

总结

您已经学会了为组件输入和输出添加类型:

  • 将接口或内联类型传给 defineProps<T>()。
  • 使用 ? 定义可选 props,使用 withDefaults 设置默认值(对象和数组使用工厂函数)。
  • defineEmits<T>() 为事件名称和负载添加类型。
  • 元组形式(event: [payload])是现代的简写语法。

常见问题解答

「使用 defineProps/defineEmits 定义带类型的 Props 与 Emits」课时是免费的吗?

是的 — 「使用 defineProps/defineEmits 定义带类型的 Props 与 Emits」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Vue Academy 课程的其余内容,请升级到 CoddyKit PRO。 Vue Academy 课程共包含 4 节课。

「使用 defineProps/defineEmits 定义带类型的 Props 与 Emits」这节课中我会学到什么?

泛型 defineProps ()、复杂类型、可选 props,以及事件触发的类型声明 你通过在浏览器中直接运行的动手代码来练习 Vue Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Vue Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Vue Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「使用 defineProps/defineEmits 定义带类型的 Props 与 Emits」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Vue Academy 课中编写并运行代码吗?

能。每节 Vue Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 在 Vue 项目中配置 TypeScript
  2. 使用 defineProps/defineEmits 定义带类型的 Props 与 Emits
  3. 为组合式函数与 Ref 添加类型
  4. 泛型 Vue 组件
← 返回 Vue Academy