给 Vue2 自定义全局 API 一点类型提示

228 阅读2分钟

在 Vue2 项目的开发中,我们经常把常用的属性、方法挂载到 Vue 的原型上面,比如:

Vue.prototype.$foo = 'Hello, world!'

如此一来,所有组件都可以通过 this.$foo 访问该属性(原型链委托)。虽然可以用了,但是没有类型提示,如果定义的全局属性和方法数量很多,很容易记不得属性、方法的名称,要用到的时候还得翻到定义的地方复制属性名,这个时候,类型声明文件就派上用场了。

在创建我们自己的类型声明文件之前,需要先了解如何为 vue 组件代码中的 this 提供类型声明。

细心的同学可能会发现,当我们在组件代码中访问 Vue 提供的 API 时,是自带提示的,比如:

image-20230810111516410

这里的 this 是组件实例,只要找到它的类型声明就 ok 了。我们可以跳转到其定义处,interface Vue 就是 this 的类型声明:

Kapture 2023-08-10 at 11.22.31

既然已经找到了“源头”,只要想办法把我们自定义的属性和方法,和 Vue 提供的 interface 结合起来就行了,正好,TypeScript 的 interface 就提供了这个功能,同名的 interface 会合并属性、方法:

image-20230810114834316

在项目根目录下新建 shime-global.d.ts 文件:

declare module "vue/types/vue" {
  interface Vue {
    /** 应用名称 */
    $APP_NAME: string
    /** foo */
    $foo(): void
}

为什么要加上 declare module "vue/types/vue"

因为 Vue 提供的类型声明文件位于 node_modules/vue/types/vue.d.ts ,此文件中使用了 import 和 export,导致该类型声明成为模块,外部无法与之产生“羁绊”。

如果不加,我们声明的 interface Vue { } 就是在“自娱自乐”,和 Vue 提供的 interface Vue { } 是两个不同的类型,也就不会合并。

现在来测试一下:

image-20230810115828333

可以看到,类型提示有了,我们写的文档注释也生效了,大功告成。