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

最近正在将一个使用单文件组件的 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; }>();从 选项API 的 emit 和 props 到 组合API 的 defineemit 和 defineProps 函数的基于类型语法的转换并不简单 。我也很好奇 Vue 是如何处理接口的 。
TypeScript 接口是只在设计和编译时存在的结构 。它们在JavaScript运行时之前被过滤掉,那么它们是如何影响组件的行为的呢?
我想知道是否有办法看到Vue如何解释传递给 defineEmits 和 defineProps 的通用参数 。如果你注意到文档中说你不需要导入 defineEmits 和 defineProps 函数 。这是因为它们实际上是同名的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, {inl.NETemplate: true,templateOptions: {filename},id: mockId});if (out) {writeFile(out, "utf8", content);} else {process.stdout.write(content);}});

事例地址:
https://stackblitz.com/edit/node-fzuykn?file=index.js
【Vue3中defineEmits、defineProps 是怎么做到不用引入就能直接用的】例如,有如以下组件:
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 的属性 。
作者:romaopedro 译者:前端小智 来源:logrocket
https://unicorn-utterances.com/posts/vue-composition-inspector




    推荐阅读