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

相关推荐
是罐装可乐1 小时前
前端架构知识体系:通过发布-订阅者模式解耦路由和请求
前端·架构·vue·路由
杀死那个蝈坦1 小时前
监听 Canal
java·前端·eclipse·kotlin·bootstrap·html·lua
普贤莲花1 小时前
小米面试总结20251202
面试·职场和发展
程序员小寒1 小时前
Vue.js 为什么要推出 Vapor Mode?
前端·javascript·vue.js
白菜__1 小时前
去哪儿小程序逆向分析(酒店)
前端·javascript·爬虫·网络协议·小程序·node.js
前端老曹1 小时前
Jspreadsheet CE V5 使用手册(保姆版) 二
开发语言·前端·vue.js·学习
IT_陈寒1 小时前
SpringBoot3.0实战:5个高并发场景下的性能优化技巧,让你的应用快如闪电⚡
前端·人工智能·后端
秋邱1 小时前
AR 定位技术深度解析:从 GPS 到视觉 SLAM 的轻量化实现
开发语言·前端·网络·人工智能·python·html·ar
云飞云共享云桌面1 小时前
佛山某机械加工设备工厂10个SolidWorks共享一台服务器的软硬件
大数据·运维·服务器·前端·网络·人工智能·性能优化