给团队做次TypeScript分享(九)—— 声明文件

289 阅读1分钟

声明文件

例如一般一个项目都会引入其他的依赖包(没有对应的声明文件),或者是在html中使用<script>标签引入的其他脚本,这时候在 ts 中使用时,就会报错。

这时候就需要书写对应的声明文件做类型补充,声明文件以 .d.ts 结尾。

一般第三方库都不需要我们自己写书面文件,其声明文件会包含在库中或可以通过 “@types/” + 三方库的名 下载对应的声明文件,例如

npm install @types/jquery --save-dev

如果以上都没有生效,则需要自己写对应的声明文件

全局声明文件

使用 declare 关键字

  • declare var : 声明全局变量的类型
  • declare function: 声明全局函数的类型
  • declare class : 声明全局类的类型
  • declare namespace : 声明全局带属性的对象
  • interface / type : 声明全局类型

declare var

例如我们在项目中引入 jQuery 时,我们可以使用 全局变量 $

$('#id')

这时候 ts 编译器并不知道 $ 是什么东西

这时,我们就可以使用 declare var 来声明它的类型

declare var $: (tag: string) => any;

除了declare var,还可以使用 declare let,如果变量是只读的,那么可以使用 declare const

像上面的例子,jquery 全局变量 $ 是不会改变的,而且是禁止修改的,那么我们的声明最好改成

declare const $: (tag: string) => any;

这样修改 $ 时,ts就会报错

declare function

除了全局的变量,还有全局函数

同样的,上面例子中 JQuery 的 $ 其实是个函数

那么便可以用 declare function 声明

declare function $(tag: string): any;

注意,声明语句中只能定义类型,不能有具体实现

declare class

同样的如果全局变量有个类,写对应的声明,同样的只能定义类型,不能定义具体实现

declare class User {
    constructor(name: string)
    name: string;
	age: number;
}
// ts 中就可以正常使用
let myUser = new User()

declare namespace

如果全局变量有个对象,可以使用declare namespace声明全局带属性的对象

在 declare namespace 内部,可以直接使用 function、namespace、const、class 等来声明,而不需要在其前面加 declare

declare namespace myObject {
    function show(s: string): string;
    let myInfo: number;
    class myClass {
        constructor(n:string)
        name: string
	}
    // 也可以嵌套 namespace
    namespace secondLayer{
        secondData
    }
}

这样 ts 中就可以正常使用

    console.log(myObject.myInfo.toFixed(2))
    console.log(myObject.secondLayer.secondData.length)
    myObject.show('')
    new myObject.myClass('')

也可以直接创建嵌套的命名空间

declare namespace myObject.secondLayer {
     secondData
}

interface 、 type

除了全局变量,有时候我们需要声明一个全局的类型,这时候可以在声明文件中使用 interface 和 type 声明

interface IGlobalInterface {
    name: string
}

这样就可以在全局使用 IGlobalInterface 这个接口,type同理

声明的合并

例如页面中引入了 jquery

<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

jq自己既是函数,其又有很多的属性

那么可以,

declare function jQuery(selector: string): any;
declare namespace jQuery{
    function ajax(url: string, settings?: any): void;
}

同名的声明可以合并

通过声明合并,我们可以直接扩展全局变量

例如扩展 String 类型

interface String {
    myStringFunction(): string;
}
'xxx'.myStringFunction()

也可以使用 declare namespace 给已存在的命名空间新增其他类型声明

模块的声明文件

declare module

declare module 可以声明模块

例如常用的 js-cookie npm包

import Cookies from 'js-cookie'
Cookie.get('token') // error 不存在属性"get"

可以写对应的声明文件

// 这里只是部分类型声明示例,并不是 js-cookie 完整的类型声明
declare module 'js-cookie'{
    export function get(x:string, option?:{ [key:string]: string }):void
}

如果是需要扩展原有模块的话,需要在类型声明文件中先引用原有模块,再使用 declare module 扩展原有模块

例如:

import * as thirdPartyModule from 'thirdPartyModule';

declare module 'thirdPartyModule' {
    export function otherAttr(): string;
}