第 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 小时前
Agent Skill与Rules的区别——以Cursor为例
前端·javascript·后端
Hilaku4 小时前
不要在简历上写精通 Vue3?来自面试官的真实劝退
前端·javascript·vue.js
三小河4 小时前
前端视角详解 Agent Skill
前端·javascript·后端
Aniugel4 小时前
单点登录(SSO)系统
前端
鹏多多4 小时前
移动端H5项目,还需要react-fastclick解决300ms点击延迟吗?
前端·javascript·react.js
serioyaoyao4 小时前
上万级文件一起可视化,怎么办?答案是基于 ParaView 的远程可视化
前端
万少4 小时前
端云一体 一天开发的元服务-奇趣故事匣经验分享
前端·ai编程·harmonyos
WindrunnerMax4 小时前
从零实现富文本编辑器#11-Immutable状态维护与增量渲染
前端·架构·前端框架
不想秃头的程序员4 小时前
Vue3 封装 Axios 实战:从基础到生产级,新手也能秒上手
前端·javascript·面试
数研小生5 小时前
亚马逊商品列表API详解
前端·数据库·python·pandas