通常我们在定义 ts 类型声明时,在 .d.ts 文件中使用 declare 关键字就能正常使用。这基本可以满足全局常量或者一些简单的类型定义。但是不排除更为复杂的使用条件,比如在某个模块中使用其他模块声明的类型,如果在 .d.ts 文件中使用了 import 或者 require 等方式引入了其他模块,那么 ts 就会将其视为一个模块,从而导致文件下的所有类型声明直接失效。

首先定义 global.ts,代码如下:

export interface GlobalState {
  loading: boolean;
  pageNum: number;
  pageSize: number;

此时在 typings.d.ts 中想要使用 GlobalState 这个类型,就需要引入 global.ts 这个文件,如果直接在 typings.d.ts 文件顶部引入,就会导致其中的全局声明全部失效。

// typings.d.ts
import { GlobalState } from 'global.ts';
declare interface Window {
  _store: {
    _state: any;
    _dispatch: any;

在使用 window._store 的地方就会抛出错误,_store 在类型 Window 上不存在

TypeScript ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块。相反地,如果一个文件不带有顶级的 import 或者 export 声明,那么它的内容被视为全局可见的(因此对模块也是可见的),这就是为什么有时候没有引用某个 .d.ts 文件,但是在该 .d.ts 文件内部的类型定义在其它文件中仍然能检测得到,这是因为该 .d.ts 文件定义的类型已经变成全局的了

通过创建全局命名空间的方式,将想要使用的类型声明挂载到全局命名空间上。

// 新建 global.d.ts 文件用来声明全局命名空间
import { GlobalState, GlobalDispatch } from 'global.ts';
declare namespace GlobalType {
  interface G_State extends GlobalState {}
  interface G_Dispatch extends GlobalDispatch {}
export = GlobalType;
export as namespace GlobalType;

然后在想要使用 GlobalState 类型声明的文件中,使用 GlobalType.GlobalState。

// typings.d.ts
declare interface Window {
  _store: {
    _state: GlobalType.G_State ;
    _dispatch: GlobalType.G_Dispatch ;

需要注意的是,如果全局命名空间发生了重复,重复的命名空间就会发生覆盖,且没有提示或报错,所以声明全局命名空间,一定注意不要重复。

TypeScript的 d.ts 声明文件中的 export = 语句的作用什么?

TypeScript 可以将 ts 代码生成 CommonJs 规范AMD 规范,由于两者并不兼容,所以就有了 export = 语法将两者进行统一,以至于让 ts 支持。

TypeScript的 d.ts 声明文件中的 export as namespace 语句的作用什么?

export as namespace 表示将某个命名空间挂载到全局命名空间上,从而可以通过全局变量的形式使用

挂载全局namespace

ts正确推导类型声明