Skip to main content

TypeScript 声明自定义类型模块

项目有时候修改了内置对象的原型,使它额外地拥有了一些方法,对应地要显式声明这些方法的类型,否则 TypeScript 只会用标准的 lib 去做类型检查。

下面是一个例子,让 String 增加额外的方法,同时让 TypeScript 识别到他们。

扩展 String.sayYes

下方的代码给 String 的原型增加一个 sayYes 的方法,sayYes() 会让 String 对象同意自己的表达。

String.prototype.sayYes = function () {
  console.log(`${this}, YES`)
}

调用这个方法:

'AMD'.sayYes('YES')
// AMD, YES

new String('AMD').sayYes()
// AMD, YES

现在 String 已经有 sayYes 功能了,但是 TypeScript 不认,因为 TypeScript 是依据标准库做类型检查的。

TypeScript 认为这个 String 没有 sayYes 成员

显式声明 String.sayYes

既然 TypeScript 不认这个 sayYes,那就给 String 编写额外声明 ,表明 sayYes 的存在。

TypeScript 配置文件选项 typeRoots 可以指定自定义声明。

// tsconfig.json
{
  // ...
  "compilerOptions": {
    // ...
    "typeRoots": ["./typings.d.ts"]
  }
}
// typings.d.ts
declare interface String {
  sayYes(): void
}

声明文件以 d.ts 结尾,现在 TypeScript 不会再报错了。

引用其他声明

声明文件不支持 import,如果要引用其他声明文件,则可以用 reference 命令字。

三斜杠 /// 会被编译器识别为指令 (TypeScript 三斜杠指令文档)

// tsconfig.json
{
  // ...
  "compilerOptions": {
    // ...
    "typeRoots": ["./typings.d.ts"]
  }
}
// typings.d.ts

/// <reference path="./typings_string.d.ts" />
// typings_string.d.ts
declare interface String {
  sayYes(): void
}

声明自定义模块

.d.ts 不仅可以声明类型,方法,还可以声明模块。

下方的 void_module 声明了一个不存在的模块,如果尝试 import、require 会导致 MODULE_NOT_FOUND 报错。但是 TypeScript 不会产生类型检查错误。

declare module 'void_module' {
  function voidAction();
}
// main.ts
// 类型检查通过,但是运行会报错
import { voidAction } from 'void_module';

voidAction();

附录

按指引配置了微信小程序类型库后,不需要 import 模块也有自动提示了。typeRoots 只是一种自定义声明的方式,TypeScript 还会寻找 node_modules/@types 中所有的包,解析出里面的显式声明。所以当 TypeScript 找不到一些包的类型时,会问问是否安装了 @types/XXXX

npm 微信小程序类型库