Skip to content

TS 类型声明文件

1. 什么是声明文件

.d.ts结尾的文件

2. 声明文件有什么作用

为 JS 代码提供类型声明

3. 声明文件的位置

  1. 放置到tsconfig.json配置中include字段包含的目录或者子目录的任何位置都会生效
  2. 放置到node_modules/@types文件夹中(一般手动安装的类型申明文件)
  3. 手动配置tsconfig.json中的typesRoot字段,值为数组,配置了此字段,可以指定多个目录,其余地方的类型申明文件会失效,包括 node_modules/@types下的也会失效(高优先级)
  4. 与 js 代码所在目录相同,并且名字也相同的文件。(用 ts 编写的工程发布之后的格式一般都长这样)

4. 编写声明文件

4.1 自动生成

  • 场景:你的工程是 ts 开发的,发布(编译)之后,是 js 文件,发布的是 js 文件,若发布的文件需要其他开者使用,可以使用类型声明文件来描述发布结果中的类型

配置方式:tsconfig.configdeclaration:true即可,在打包时候,就会在生成 js 时候同时生成一个同名的.d.ts声明文件

配置sourceMap:true会在生成同名的.js.map源码地图文件

4.2 手动编写

  • 场景
  1. 对已有一个用 js 编写的库,并且改动该库为 ts 成本较高,可以手动编写声明文件
  2. 对一些第三方库,他们使用 js 编写,并且他没有提供声明文件,我们可以自己手动编写声明文件(现在一般安装的库都会有声明文件)

编写细节

  • 文件名无关,只要后缀为.d.ts即可

全局声明

用于声明一些全局对象、属性、变量等

声明用declare关键字进行声明

提示

declare 关键字用来告诉编译器,某个类型是存在的,可以在当前文件中使用。

它的主要作用,就是让当前文件可以使用其他文件声明的类型。举例来说,自己的脚本使用外部库定义的函数,编译器会因为不知道外部函数的类型定义而报错,这时就可以在自己的脚本里面使用 declare 关键字,告诉编译器外部函数的类型。这样的话,编译单个脚本就不会因为使用了外部类型而报错。

例如:

ts
// 声明一个nodejs中的console
interface Console {
  log: (message?: string) => void;
  error: (message?: string) => void;
}

declare var console: Console;

// 或者 通过命名空间
declare namespace console {
  function log(message: string): void;
  function error(message: string): void;
}

类型声明文件时写给 ts 编译器看的,不影响运行

类型声明文件只能声明类型,申明类型时候不能赋值

namespace:表示命名空间,可以将其认定为是一个对象,明明 空间中的内容,必须通过命名空间.成员名访问 如果想把变量、函数、类组织在一起,可以将 declare 与 module 或 namespace 一起使用。

模块声明

语法

typescript
declare module "moduleA" {
  export interface Url {
    protocol?: string;
    hostname?: string;
    pathname?: string;
  }
}

提示

declare moduledeclare namespace 里面,加不加 export 关键字都可以。

5. 一些常见的declare语法

declare 关键字可以描述以下类型。

  • 变量(const、let、var 命令声明)
  • type 或者 interface 命令声明的类型
  • class
  • enum
  • 函数(function)
  • 模块(module)
  • 命名空间(namespace)

declare class 示例

typescript
declare class Animal {
  constructor(name: string);
  eat(): void;
  sleep(): void;
}

declare module,declare namespace 示例

typescript
declare namespace AnimalLib {
  class Animal {
    constructor(name: string);
    eat(): void;
    sleep(): void;
  }

  type Animals = "Fish" | "Dog";
}

// 或者
declare module AnimalLib {
  class Animal {
    constructor(name: string);
    eat(): void;
    sleep(): void;
  }

  type Animals = "Fish" | "Dog";
}

declare global 示例

如果要为 JavaScript 引擎的原生对象添加属性和方法,可以使用 declare global {}语法。

typescript
export {};

declare global {
  interface String {
    toSmallString(): string;
  }
}

String.prototype.toSmallString = (): string => {
  // 具体实现
  return "";
};

上面示例中,为 JavaScript 原生的 String 对象添加了 toSmallString()方法。declare global 给出这个新增方法的类型描述。

这个示例第一行的空导出语句 export {},作用是强制编译器将这个脚本当作模块处理。这是因为 declare global 必须用在模块里面。

下面的示例是为 window 对象添加一个属性 myAppConfig。

typescript
export {};

declare global {
  interface window {
    myAppConfig: object;
  }
}

const config = window.myAppConfig;

declare global 只能扩充现有对象的类型描述,不能增加新的顶层类型。

declare enum 示例

declare 关键字给出 enum 类型描述的例子如下,下面的写法都是允许的。

typescript
declare enum E1 {
  A,
  B,
}

declare enum E2 {
  A = 0,
  B = 1,
}

declare const enum E3 {
  A,
  B,
}

declare const enum E4 {
  A = 0,
  B = 1,
}

declare module 用于类型声明文件

我们可以为每个模块脚本,定义一个.d.ts 文件,把该脚本用到的类型定义都放在这个文件里面。但是,更方便的做法是为整个项目,定义一个大的.d.ts 文件,在这个文件里面使用 declare module 定义每个模块脚本的类型。

下面的示例是 node.d.ts 文件的一部分。

typescript
declare module "url" {
  export interface Url {
    protocol?: string;
    hostname?: string;
    pathname?: string;
  }

  export function parse(
    urlStr: string,
    parseQueryString?,
    slashesDenoteHost?
  ): Url;
}

declare module "path" {
  export function normalize(p: string): string;
  export function join(...paths: any[]): string;
  export var sep: string;
}

上面示例中,url 和 path 都是单独的模块脚本,但是它们的类型都定义在 node.d.ts 这个文件里面。

使用时,自己的脚本使用三斜杠命令,加载这个类型声明文件。

typescript
/// <reference path="node.d.ts"/>

如果没有上面这一行命令,自己的脚本使用外部模块时,就需要在脚本里面使用 declare 命令单独给出外部模块的类型。

原文地址

TypeScript 教程 阮一峰