TypeScript系列🔥, 通过vue3实例说说declare module语法怎么用[🦕模块声明篇]

10,268 阅读3分钟

欠你们的

本系列文章是我20年开始写的, 这个模块声明也是本系列的最后一课, 中间因为时间安排间隔了1年, 当时答应大家要补充的, 现在来还债😊.

中间的时间我写了vue3的入门教程, 现在写了一半了吧, 带视频的, 如果有需要的小伙伴可以去看看. www.yuque.com/books/share… 《vue3知识点"精选"》

往期目录

第一课, 体验typescript

第二课, 基础类型和入门高级类型

第三课, 泛型

第四课, 解读高级类型

第五课, 命名空间(namespace)是什么

特别篇, 在vue3🔥源码中学会typescript🦕 - "is"

第六课, 什么是声明文件(declare)? 🦕 - 全局声明篇

第七课, 通过vue3实例说说declare module语法怎么用🦕模块声明篇

新开发vscode插件: ⚡any-type, 一键json到ts类型

使用场景

npm下载的"包"自带了声明文件, 如果我们需要对其类型声明进行扩展就可以使用"declare module"语法.

让vue3支持this.$axios

// main.ts
app.config.globalProperties.$axios = axios;

功能上我们实现了"this.axios",但是ts并不能自动推断出我们添加了axios", 但是ts并不能自动推断出我们添加了axios字段, 所以添加如下声明文件:

// global.d.ts

// axios的实例类型
import { AxiosInstance } from 'axios'

// 声明要扩充@vue/runtime-core包的声明.
// 这里扩充"ComponentCustomProperties"接口, 因为他是vue3中实例的属性的类型.
declare module '@vue/runtime-core' {
  
  // 给`this.$http`提供类型
  interface ComponentCustomProperties {
    $axios: AxiosInstance;
  }
}

这里扩充"ComponentCustomProperties"接口, 因为他是vue3中实例的属性的类型.

更全面的例子

上面的例子中我们扩充了原声明中的interface, 但是如果导出是一个Class我们该如何写呢? 下面我们对"any-touch"的类型进行扩充, 这里"any-touch"的默认导出是一个Class. 假设我们对"any-touch"的代码做了如下修改:

  1. 导出增加"aaa"变量, 是string类型.
  2. 类的实例增加"bbb"属性, 是number类型.
  3. 类增加静态属性"ccc", 是个函数.
// global.d.ts

// AnyTouch一定要导入, 因为只有导入才是扩充, 不导入就会变成覆盖.
import AnyTouch from 'any-touch'

declare module 'any-touch' {
    // 导出增加"aaa"变量, 是个字符串.
    export const aaa: string;
		
    export default class {
      // 类增加静态属性"ccc", 是个函数.
      static ccc:()=>void
      // 类的实例增加"bbb"属性, 是number类型.
      bbb: number
    }
}

注意: AnyTouch一定要导入, 因为只有导入才是类型扩充, 不导入就会变成覆盖. ​

测试下, 类型都已经正确的添加:

// index.ts
import AT,{aaa} from 'any-touch';

const s = aaa.substr(0,1);

const at = new AT();
at.bbb = 123;

AT.ccc = ()=>{};

对非ts/js文件模块进行类型扩充

ts只支持模块的导入导出, 但是有些时候你可能需要引入css/html等文件, 这时候就需要用通配符让ts把他们当做模块, 下面是对".vue"文件的导入支持(来自vue官方):

// global.d.ts
declare module '*.vue' {
  import { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}
// App.vue
// 可以识别vue文件
import X1 from './X1.vue';
export default defineComponent({
	components:{X1}
})

声明把vue文件当做模块, 同时标注模块的默认导出是"component"类型. 这样在vue的components字段中注册模块才可以正确识别类型.

vuex

下面是vuex官方提供的, 在vue的实例上声明增加$store属性, 有了前面的支持, 看这个应该很轻松.

// vuex.d.ts

import { ComponentCustomProperties } from 'vue'
import { Store } from 'vuex'

// 声明要扩充@vue/runtime-core包的声明
declare module '@vue/runtime-core' {
  // declare your own store states
  interface State {
    count: number
  }

  // provide typings for `this.$store`
  interface ComponentCustomProperties {
    $store: Store<State>
  }
}

并非全部内容

到此声明的内容就都结束了, 但实际上还有些"模块声明"的方式并没有覆盖到, 因为本课程的最终目的是基于vue3开发暂不涉猎npm包的开发,所以其他的内容就不展开了, 有需要的同学可以看ts文档来学习, 有了本文的基础, 相信你会很轻松学会更多.

微信群

感谢大家的阅读, 如有疑问可以加我微信, 我拉你进入微信群(由于腾讯对微信群的100人限制, 超过100人后必须由群成员拉入)

github

我个人的开源都是基于ts的, 欢迎大家访问github.com/any86

image.png