我对 Typescript 不太有经验,但我的印象是,如果声明的类型正确,它们应该与它们所描述的对象的运行时结构相匹配。我正在重构 Vue 代码库(并将其迁移到打字稿),其中 Vue 组件定义在从 SFC 导入后被修改。
原始代码期望导入的组件定义具有一定的结构(具体来说具有“props”字段),它确实如此。但是,将其移至打字稿并启用类型检查后,导入的组件定义的类型为 DefineComponent -- https://github.com/vuejs/core/blob/574c3e63bbb764c82fd7228eac979bb3e7fa731d/packages/runtime-core/src/apiDefineComponent.ts #L44 具有完全不同的结构并且没有“props”字段。
我的问题是为什么会出现这种差异。
我们可以通过创建 vue 3 脚手架项目来观察有限环境中的行为 - https://cli.vuejs.org/guide/creating-a-project.html然后将 main.ts 修改为以下内容:
import { createApp, defineComponent } from 'vue'
const comp = defineComponent({props: ['msg'], render:()=>"HELLO WORLD"})
console.log(comp)
new comp()
createApp(comp).mount('#app')
这段代码编译正确,具体来说,
comp
变量可以用作构造函数(defineComponent
的类型声明表明它是)。但是,在运行时,代码会失败,因为 comp
指向
{
"props": ["msg"],
"render": () => () => "HELLO WORLD"
}
我期望运行时
comp
的值与声明的类型兼容,但事实并非如此。
即使组件是导入的 SFC 并且未内联定义,此行为也是相同的。
再苦苦挣扎之后更新:
defineComponent
的返回类型需要为 DefineComponent
类型,因为它可以用作 TSX 基于值的元素 - https://www.typescriptlang.org/docs/handbook/jsx.html 。上面引用的 tsx 文档指定了如何对元素进行类型检查。即,元素名称必须在 ts 范围内,并且必须是其签名与提供给 tsx 元素的属性匹配的构造函数。因此,在这种情况下,让结果的类型与选项对象(结果实际上是在运行时的)兼容将不起作用。