第 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 自动推断,与宏无关。

相关推荐
老华带你飞7 小时前
学生宿舍管理|基于java + vue学生宿舍管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
一天前7 小时前
一个功能强大的 React Native 拖拽排序组件库,支持单列和多列布局,提供流畅的拖拽体验和自动滚动功能
前端
OpenTiny社区7 小时前
2025年OpenTiny年度人气贡献者评选正式开始
前端·javascript·vue.js
JosieBook8 小时前
【Vue】04 Vue技术——Vue 模板语法详解:插值与指令
前端·javascript·vue.js
汤姆Tom8 小时前
硬核指南:Volta —— 重新定义 JavaScript 工具链管理
前端·敏捷开发·命令行
Goodbaibaibai8 小时前
Element自定义主题色
前端·css·css3
INGg__8 小时前
Java面试现场:从简单到复杂
java·面试·技术
灰海8 小时前
为什么给<a>标签设置了download属性, 浏览器没有下载而是打开新标签!!
前端·vue·html·下载·download
1024肥宅8 小时前
面试和算法:常见面试题实现与深度解析
前端·javascript·面试
float_六七8 小时前
行级与块级元素:核心区别与应用场景
开发语言·前端·javascript