第 27 题:Vue3 + TS 类型推断(Props 类型推导、Emit 类型推导、Setup 返回值类型)

第 26 题:Vue3 + TS 类型推断(Props 类型推导、Emit 类型推导、Setup 返回值类型)


🎯 一、核心回答(面试官最想听)

Vue3 + TS 的类型推断能力主要依赖 宏(compile-time macro)+ 泛型(generic)+ 类型收窄(narrowing)

最常考:

  1. defineProps 会自动推断 props 类型

    来自编译器(vue-tsc / Volar)在编译时分析宏。

  2. defineEmits 会自动推断 emit 的事件名和参数类型。

  3. setup 返回值的类型推断 由 TS 自动完成,和 Vue3 的宏无关。

  4. Props 类型推断依赖两种写法:

    • 基于类型(最常用)
    • 基于运行时(runTime props)

🎯 二、Vue3 TS 类型推断深度原理(深入讲,面试加分)


1️⃣ defineProps 编译后变成类型声明(编译时宏)

示例:

typescript 复制代码
const props = defineProps<{
  name: string
  age?: number
}>()

编译后(简化):

typescript 复制代码
// 编译器把 defineProps 的类型直接注入 TS 中
interface Props {
  name: string
  age?: number
}
const props: Props

🚀 本质:

defineProps 并不是 runtime 代码,而是 compile-time 宏。

编译器会分析宏参数,把类型直接注入到组件类型中。


2️⃣ defineEmits 类型推断机制

typescript 复制代码
const emit = defineEmits<{
  (e: 'change', value: number): void
  (e: 'delete', id: string): void
}>()

TS 推断出:

scss 复制代码
emit('change', 123)
emit('delete', 'abc')

如果写错:

arduino 复制代码
emit('change', 'xxx') // ❌ 报错,参数类型不对

✨ defineEmits 编译原理:

会生成两个重要东西:

  1. 事件名联合类型 'change' | 'delete'
  2. 事件函数重载类型推断

这使得 TS 能在 emit 时做严格校验。


3️⃣ 运行时 Props 的自动推导能力

Vue3 宏也能推导 runtime props:

javascript 复制代码
const props = defineProps({
  title: String,
  count: Number,
  isActive: Boolean
})

TS 会推断为:

typescript 复制代码
{
  title?: string,
  count?: number,
  isActive?: boolean
}

注意:

所有 runtime 声明的 props 都变成可选,因为父组件可以不传。


4️⃣ 使用 withDefaults 做默认值推断

php 复制代码
const props = withDefaults(
  defineProps<{
    username: string
    pageSize?: number
  }>(),
  {
    pageSize: 20
  }
)

推断结果:

  • pageSize 不再是 number | undefined
  • 自动变成 number

5️⃣ setup 返回值类型推断

Vue 的 setup:

csharp 复制代码
const count = ref(0)

function add() {}

return { count, add }

推断为:

typescript 复制代码
{
  count: Ref<number>
  add: () => void
}

Vue 会自动 unwrap ref 到模板中,但 TS 保留 Ref 类型。


🎯 三、代码示例(完整 TS + Props + Emits)


1)组合 Prop + Emit:

php 复制代码
<script setup lang="ts">
const props = defineProps<{
  value: string
  maxLength?: number
}>()

const emit = defineEmits<{
  (e: 'update:value', v: string): void
  (e: 'reachMax'): void
}>()

function input(v: string) {
  if (v.length > (props.maxLength ?? Infinity)) {
    emit('reachMax')
  }
  emit('update:value', v)
}
</script>

全部类型都会自动推断,无需手写 any。


🎯 四、面试官高频追问 & 你该怎么答


❓1:defineProps 为什么不是一个真正的函数?为什么只能在

高分回答:
因为 defineProps 是 编译器宏,不是运行时函数,它只在编译期生效。
Vue 编译器直接将 defineProps 的类型写入组件类型系统。


❓2:defineProps 的类型参数和运行时参数同时写,会怎样?

例子:

css 复制代码
defineProps<{
  name: string
}>({
  name: Number
})

结果:类型冲突,TS 会报错,因为宏不允许有两个来源。


❓3:和 Vue2 的 props + emit 相比,Vue3 的 TS 强在哪里?

高频 + 加分回答:

Vue3 做到了:

  • 事件名称的自动补全
  • 参数类型自动检测
  • props 类型自动推导
  • default 值变窄(withDefaults)
  • emit 可写多重 overload(相当专业)

Vue2 用 TS 非常吃力,Vue3 解决了痛点。


❓4:有类型推断的 defineModel(v-model 语法糖)是什么?

Vue3.4 新增:

c 复制代码
const model = defineModel<string>()

自动推断:

  • modelValue 类型
  • update:modelValue 参数类型

这是 Vue TS 体验最强的一部分。


🎯 五、高分总结(面试直接背)

Vue3 的 defineProps / defineEmits / defineModel 都是编译期宏,不存在于运行时代码中。

它们通过 TS 泛型 + 编译器静态分析,实现 Props、Emit、v-model 的完整类型推断,是 Vue3 与 TS 最强结合点。

运行时 props 写法也可以推断类型,但不如泛型写法强。

setup 返回值由 TS 自动推断,与宏无关。

相关推荐
羊小猪~~4 小时前
【QT】--文件操作
前端·数据库·c++·后端·qt·qt6.3
石去皿5 小时前
大模型面试常见问答
人工智能·面试·职场和发展
晚风资源组5 小时前
CSS文字和图片在容器内垂直居中的简单方法
前端·css·css3
Miketutu5 小时前
Flutter学习 - 组件通信与网络请求Dio
开发语言·前端·javascript
黄晓琪6 小时前
Java AQS底层原理:面试深度解析(附实战避坑)
java·开发语言·面试
光影少年7 小时前
前端如何调用gpu渲染,提升gpu渲染
前端·aigc·web·ai编程
PaQiuQiu7 小时前
GitHub 开源分享 | Coding Interview University
面试·开源·github
Surplusx7 小时前
运用VS Code前端开发工具完成网页头部导航栏
前端·html
小宇的天下8 小时前
Calibre 3Dstack --每日一个命令day13【enclosure】(3-13)
服务器·前端·数据库
一只小bit9 小时前
Qt 文件:QFile 文件读写与管理教程
前端·c++·qt·gui