Typescript 类型声明的扩展

2,558 阅读2分钟

Typescript 的类型声明可以扩展全局和第三方库的现有类型。第三方库自己拥有类型说明或在 @types 包中有类型说明,但有时第三方库没有提供累心声明或者类型不满足我们的要求,就需要我们自己编写类型声明。

大体来说,类型声明分为全局和模块,分别有不同的使用场景和方法。

全局声明指写在不包含export的文件中的类型声明(不限于.d.ts文件,但我们通常使用这个后缀),全局声明被编译器自动检测,自动生效。

模块声明指写在包含export的文件中的类型声明,需要被引入后才能生效。

声明全局变量

全局变量需要在全局声明文件中声明,比如常用的 global.d.ts 文件:

declare let a: number

这样在其它地方(全局或模块),就可以使用声明的变量,比如:

a = 1

需要注意的是,声明全局变量时可以赋值:declare let a = 0,但这里的赋值没有实际效果,只是能给编译器进行类型推断,此时a的实际值为undefined

如果需要声明的变量是一个对象,那么可以使用namespace关键词:

declare namespace a {
  let x: number
}

等效于:

declare let f: {
  x: number
  y: number
}

namespace的不同之处在于其可以通过export来使这个变量称谓一个模块,比如:

declare namespace a {
  export { x } from 'x'
}

此时声明的a就是一个包含成员x的对象,需要注意的是,此时a变成了一个模块,这个 namespace 内部使用 let 声明的变量不会被导出,就像是普通的模块那样。

扩展模块

对于 node_modules 中的第三方库,或是别人写的模块不方便直接修改代码的,可以通过扩展模块的方式声明额外变量或成员。

示例:

a.ts

interface A {
  x: number
}

export { A }

index.ts

import { A } from 'a'

declare module 'a' {
  interface A {
    y?: number
  }
}

let a = { x: 0, y: 0 }

export { a }

通过关键词declare module来扩展模块。需要注意的是,扩展模块只能在模块中声明。也就是说,如果再全局声明中使用declare module,会被识别为对这个模块的整体声明,直接覆盖原本的声明。

添加类型声明

有时候第三方库没有提供声明文件,我们可以在全局声明中为其添加声明。

示例:

declare module 'a' {
    export interface A {
        x: number
    }
}

也可以不需要添加实质内容,此时模块会被识别为any,比如:

declare module 'a'