跳至主要內容

typescript声明文件

Emilia Zhen大约 5 分钟js

声明文件

通常我们会把声明语句放到一个单独的 xx.d.ts 文件中

/path/to/project
├─ src
│  ├─ index.ts
│  └─ jQuery.d.ts
└─ tsconfig.json

第三方声明文件

声明文件查找open in new window 搜索已经定义好了的声明文件,直接用 npm 安装

npm install @types/jquery --save-dev

书写声明文件

全局变量

declare var 声明全局变量

declare const jQuery: (selector: string) => any

declare function 声明全局方法

declare function jQuery(selector: string): any

declare class 声明全局类

declare class Animal {
  name: string
  constructor(name: string)
  sayHi(): string
}

declare enum 声明全局枚举类型

declare enum Directions {
  Up,
  Down,
  Left,
  Right,
}

declare namespace 声明(含有子属性的)全局对象 namespace是早期为了解决模块化而创造的关键字,中文名称为命名空间
在早期还没有 ES6 时,ts 提供了一种模块化方案,使用module关键字表示内部模块。但后来ES6也使用了module关键字,ts为了兼容 ES6,使用namespace替代了自己的module。 推荐使用 ES6 的模块化方案

declare namespace jQuery {
  function ajax(url: string, settings?: any): void
  const version: number
  class Event {
    blur(eventType: EventType): void
  }
  enum EventType {
    CustomClick,
  }
  namespace fn {
    function extend(object: any): void
  }
}

interface 和 type 声明全局类型

npm 包

给一个npm包创建声明文件前先看看它的声明文件是否存在,一般来说可能存在与两个地方:

  1. 与该npm包绑定在一起。判断依据是package.json中有types字段,或者有一个index.d.ts声明文件;
  2. 发布到@type里。尝试安装下对应的@type 包即可

若以上两种都没找到对应的声明文件,就需要自己为它写声明文件

  1. 可以创建一个node_modules/@types/xxxx/index.d.ts文件存放xxx模块的声明文件,但目录不稳定,而且无法保存到仓库中
  2. 创建一个types目录,来管理自己写的声明文件,将xxx的声明放到types/xxx/index/d/ts中,这种方式需要配置下tsconfig.json中的pathsbaseUrl字段
// tsconfig.json
{
  "compilerOptions": {
    "module": "commonjs",
    "baseUrl": "./",
    "paths": {
      "*": ["types/*"]
    }
  }
}

配置后,通过import导入的xxx时,会去types目录下寻找对应的模块声明文件

export const name: string
export function getName(): string
export class Animal {
  constructor(name: string)
  sayHi(): string
}
export enum Directions {
  Up,
  Down,
  Left,
  Right,
}
export interface Options {
  data: any
}
export namespace foo {
  const name: string
  namespace bar {
    function baz(): string
  }
}

UMD 库

既可以通过<script>标签引入,又可以通过import导入的库,称为UMD库 相比npm包的类型声明文件,我们需要额外声明一个全局变量,ts提供了语法export as namespace

export as namespace foo
export default foo
declare function foo(): string
declare namespace foo {
  const bar: number
}

在 npm 包或 UMD 库中扩展全局标量

对于npm包UMD库,如果导入此库后会宽展全局变量,需要使用declare global在声明文件中扩展全局变量的类型

declare global {
  interface String {
    prependHello(): string
  }
}
export {}

模块插件

有时通过 import 导入一个模块插件,可以改变另一个原有模块的结构。此时如果原有模块已经有了类型声明文件,而插件模块没有类型声明文件,就会导致类型不完整,缺少插件部分的类型。ts 提供了 declare module 可以用来扩展原有模块的类型

import * as moment from 'moment'
declare module 'moment' {
  export function foo(): moment.CalendarKey
}

声明文件中的依赖

除了可以在声明文件中通过import导入另一个声明文件中的类型外,还可以用三斜线指令来导入另一个声明文件

  1. 书写一个全局变量的声明文件 在全局变量的声明文件中,是不允许出现import,export关键字的,一旦出现了,会被视为一个npm包UMD库///后面使用 xml 格式添加了对jquery类型的依赖,可以在声明文件中使用JQuery.AjaxSerring类型了 ///指令必须放在文件的最顶端
/// <reference types="jquery" />
declare function foo(options: JQuery.AjaxSettings): string
  1. 依赖一个全局变量的声明文件 引入的 node 中的类型都是全局变量的类型,它们没有办法通过import来导入,需要通过///来引入。在src/index.tsfoo(global.process)
/// <reference types="node" />
export function foo(p: NodeJS.Process): string

自动生成声明文件

如果库的源码本身就是由ts写的,那么在使用tsc脚本将ts编译为js时,添加declaration选项,就可以同时也生成.d.ts声明文件了
可以在命令行添加--declaration-d,或者在tsconfing.json中添加declaration选项,添加outDir选项,将ts文件的编译结果输出到lib目录下

{
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "lib",
    "declaration": true
  }
}

发布声明文件

如果声明文件是通过tsc自动生成的,那么无需做任何配置,只需把编译好的文件也发布到npm上,使用放就可以获取到类型的提示了 如果是手动写的声明文件那么需要满足一下条件之一,才能被正确的识别

  1. package.json中的typestypings字段指定一个类型声明文件地址
  2. 在项目根目录下,编写一个index.d.ts文件
  3. 针对入口文件(package.json中main字段指定的入口文件),编写一个同名不同后缀的.d.ts文件
{
  "name": "xxx",
  "version": "1.0.0",
  "main": "lib/index.js",
  "types": "xxx.d.ts"
}

如果我们是在给别人的仓库添加类型声明文件,但原作者不愿意合并,那么需要将声明文件发布到@types下 暴露在最外层的interfacetype会作为全局类型作用于整个项目中,我们应该尽可能得减少全局变量或全局类型的数量。最好将他们放在namespace

declare namespace jQuery {
  interface AjaxSettings {
    method?: 'GET' | 'POST'
    data?: any
  }
  function ajax(url: string, settings?: AjaxSettings): void
}

// src/index.ts
let settings: jQuery.AjaxSettings = {
  method: 'POST',
  data: {
    name: 'foo',
  },
}
jQuery.ajax('/api/post_something', settings)