Vue3中defineEmits、defineProps|Vue3中defineEmits、defineProps 是怎么做到不用引入就能直接用的

新出了一个系列:Vue2与Vue3 技巧小册

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势,学习途径等等。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。
最近正在将一个使用单文件组件的 Options API 的 Vue2 JavaScript 项目升级为 Vue3 typescript,并利用 Composition API 的优势。
比如,下面这种 选项API 方式:
export default { props: { name: { type: String, required: true. } }, emits: ['someEvent', 'increaseBy'] };

我们将它转成 组合API 方式:
const props = defineProps<{ name: string; }>(); const emit = defineEmits<{ (event: 'someEvent): void; (event: 'increaseBy', value: number): void; }>();

【Vue3中defineEmits、defineProps|Vue3中defineEmits、defineProps 是怎么做到不用引入就能直接用的】从 选项API 的 emitprops 到 组合API 的 defineemitdefineProps 函数的基于类型语法的转换并不简单。我也很好奇 Vue 是如何处理接口的。
TypeScript 接口是只在设计和编译时存在的结构。它们在JavaScript运行时之前被过滤掉,那么它们是如何影响组件的行为的呢?
我想知道是否有办法看到Vue如何解释传递给 defineEmitsdefineProps 的通用参数。如果你注意到文档中说你不需要导入 defineEmitsdefineProps 函数。这是因为它们实际上是同名的JavaScript函数的宏。在进行完整的 TypeScript 传递之前,Vue webpack插件使用TypeScript的 AST(抽象语法树)来推导JavaScript版本的函数选项。
如果不是因为宏:
defineProps<{ prop1: string; prop2: number; }>();

就会变成:
defineProps();

这样就会导致参数缺失的错误。
如果看一下Vue的 SFC(单文件组件)编译器源代码,有一个叫做 compileScript 的函数。我开始尝试用最少的参数来调用这个函数,这样就不会出错,并模拟任何不重要的必要参数。最终发现了另一个叫 parse 的函数。这给了我所需的大部分参数,只剩下要mock的组件 id
这里有一个小脚本,它接收SFC的 .vue文件并输出 Vue 如何解释 TypeScript。
import { readFile, writeFile } from "fs"; import parseArgs from "minimist"; import { parse, compileScript } from "@vue/compiler-sfc"; const { file, out } = parseArgs(process.argv.slice(2), { string: ["file", "out"], alias: { file: "f", out: "o" } }); const filename = file; const mockId = "xxxxxxxx"; readFile(filename, "utf8", (err, data) => { const { descriptor } = parse(data, { filename }); const { content } = compileScript(descriptor, { inlineTemplate: true, templateOptions: { filename }, id: mockId }); if (out) { writeFile(out, "utf8", content); } else { process.stdout.write(content); } });

事例地址:https://stackblitz.com/edit/n...
例如,有如以下组件:
interface Bar { prop1: string; prop2: number; }defineProps<{ bar: Bar; bars: Bar[]; asdf1?: boolean; asdf2: string[]; }>();

输出:
interface Bar { prop1: string; prop2: number; }export default /*#__PURE__*/_defineComponent({ __name: 'demo', props: { bar: { type: Object, required: true }, bars: { type: Array, required: true }, asdf1: { type: Boolean, required: false }, asdf2: { type: Array, required: true } }, setup(__props: any) { return (_ctx: any,_cache: any) => { return (_openBlock(), _createElementBlock("div")) } }

正如上面所看到的,SFC编译器采用TypeScript类型信息,并建立了 props 对象。原始类型是一对一的。接口变成对象,而 ? 可选语法驱动 required 的属性。
代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。
作者:romaopedro 译者:前端小智 来源:logrocket
https://unicorn-utterances.co...
交流
有梦想,有干货,微信搜索 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。
本文 GitHub https://github.com/qq44924588... 已收录,有一线大厂面试完整考点、资料以及我的系列文章。
Vue3中defineEmits、defineProps|Vue3中defineEmits、defineProps 是怎么做到不用引入就能直接用的
文章图片

    推荐阅读