3

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

 2 years ago
source link: https://segmentfault.com/a/1190000040699170
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

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

第一课, 体验typescript

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

第三课, 泛型

第四课, 解读高级类型

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

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

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

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

让vue3支持this.$axios

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

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

// global.d.ts

import { ComponentCustomProperties } from 'vue'

// 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官方提供的, 在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的, 欢迎大家访问https://github.com/any86

image.png


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK