# 模块声明

# export = 和 import = require()

CommonJS和AMD的环境里都有一个exports变量,这个变量包含了一个模块的所有导出内容。

CommonJS和AMD的exports都可以被赋值为一个对象, 这种情况下其作用就类似于 es6 语法里的默认导出,即 export default语法了。虽然作用相似,但是 export default 语法并不能兼容CommonJS和AMD的exports。

为了支持CommonJS和AMD的exports, TypeScript提供了export =语法。

export =语法定义一个模块的导出对象。 这里的对象一词指的是类,接口,命名空间,函数或枚举。

若使用export =导出一个模块,则必须使用TypeScript的特定语法import module = require("module")来导入此模块。


ZipCodeValidator.ts

let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {
    isAcceptable(s: string) {
        return s.length === 5 && numberRegexp.test(s);
    }
}
export = ZipCodeValidator;

1
2
3
4
5
6
7
8
9
10
11
Test.ts


import zip = require("./ZipCodeValidator");

// Some samples to try
let strings = ["Hello", "98052", "101"];

// Validators to use
let validator = new zip();

// Show whether each string passed each validator
strings.forEach(s => {
  console.log(`"${ s }" - ${ validator.isAcceptable(s) ? "matches" : "does not match" }`);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 外部模块

在Node.js里大部分工作是通过加载一个或多个模块实现的。 我们可以使用顶级的 export声明来为每个模块都定义一个.d.ts文件,但最好还是写在一个大的.d.ts文件里。 我们使用与构造一个外部命名空间相似的方法,但是这里使用 module关键字并且把名字用引号括起来,方便之后import。 例如:

node.d.ts (simplified excerpt)


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 let sep: string;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

现在我们可以/// <reference> node.d.ts并且使用import url = require("url");或import * as URL from "url"加载模块。

/// <reference path="node.d.ts"/>
import * as URL from "url";
let myUrl = URL.parse("http://www.typescriptlang.org");
1
2
3

# 外部模块简写

假如你不想在使用一个新模块之前花时间去编写声明,你可以采用声明的简写形式以便能够快速使用它。


declarations.d.ts
declare module "hot-new-module";
1
2
3

简写模块里所有导出的类型将是any。


import x, {y} from "hot-new-module";
x(y);

1
2
3
4

# 模块声明通配符

某些模块加载器如SystemJS 和 AMD支持导入非JavaScript内容。 它们通常会使用一个前缀或后缀来表示特殊的加载语法。 模块声明通配符可以用来表示这些情况。

declare module "*!text" {
    const content: string;
    export default content;
}
// Some do it the other way around.
declare module "json!*" {
    const value: any;
    export default value;
}
1
2
3
4
5
6
7
8
9

现在你可以就导入匹配"!text"或"json!"的内容了。

import fileContent from "./xyz.txt!text";
import data from "json!http://example.com/data.json";
console.log(data, fileContent);
1
2
3

# UMD模块

有些模块被设计成兼容多个模块加载器,或者不使用模块加载器(全局变量)。 它们以 UMD模块为代表。 这些库可以通过导入的形式或全局变量的形式访问。

math-lib.d.ts


export function isPrime(x: number): boolean;
export as namespace mathLib;//  注意这句的含义

1
2
3
4
5
6

之后,这个库可以在某个模块里通过导入来使用:

import { isPrime } from "math-lib";
isPrime(2);
mathLib.isPrime(2); // 错误: 不能在模块内使用全局定义。

理解下这句 错误: 不能在模块内使用全局定义。。。

因为该文件有 import,所以它是模块,模块内不能用全局变量
1
2
3
4
5
6
7

它同样可以通过全局变量的形式使用,但只能在某个脚本(指不带有模块导入import或导出 export的脚本文件)里。

mathLib.isPrime(2);

1
2

# 文件声明

  1. tslang.cs (opens new window)
  2. ts入门教程 (opens new window)
  3. FAQ (opens new window)

# 模块类的库

模块化库通常至少具有以下一些内容:

  • 无条件调用require或define
  • import * as a from 'b';类似or 的声明export c;
  • 分配给exports或module.exports

模块库的模版共有4个

  1. 如果您的模块可以像函数一样调用,则使用模板module-function.d.ts (opens new window)
const x = require("foo");
// Note: calling 'x' as a function
const y = x(42);
1
2
3
  1. 如果您的模块可以使用new的方式构建,则使用module-class.d.ts (opens new window)
const x = require("bar");
// Note: using 'new' operator on the imported variable
const y = new x("hello");
1
2
3
  1. 如果您有一个模块,在导入时使用 template 对其他模块进行更改 则可以使用 module-plugin.d.ts (opens new window)
import { greeter } from "super-greeter";
// Normal Greeter API
greeter(2);
greeter("Hello world");
// Now we extend the object with a new function at runtime
import "hyper-super-greeter"; // 对原有模块进行了扩展
greeter.hyperGreet();
1
2
3
4
5
6
7
  1. 正常模块Modules .d.ts (opens new window)
// js
const maxInterval = 12;
function getArrayLength(arr) {
  return arr.length;
}
module.exports = {
  getArrayLength,
  maxInterval,
};
// 类型文件

export function getArrayLength(arr: any[]): number;
export const maxInterval: 12;
1
2
3
4
5
6
7
8
9
10
11
12
13

# 全局类型的库 比如jQuery

在html代码里这样引入 <script src="http://a.great.cdn.for/jQuery.js"></script> 再js中这样使用

$(() => {
  console.log("hello!");
});
1
2
3

实现这种库的类型文件可以使用模版Global.d.ts (opens new window)

# UMD类的 库示例

UMD类的库可以使用module-plugin.d.ts模板。

# 使用依赖项

如何将别的库的类型导入到自己的库的类型声明文件中

  1. 如果自己的库依赖全局库请使用/// <reference types="..." />指令

/// <reference types="someLib" />
function getThing(): someLib.thing;

1
2
3
4
  1. 如果自己库依赖依赖于别的模块库,请使用以下import
import * as moment from "moment";
function getThing(): moment;
1
2
  1. 如果自己的全局库依赖别的 UMD 模块 ,请使用/// <reference types指令:
/// <reference types="moment" />
function getThing(): moment;

1
2
3
  1. 如果自己的的模块或 UMD 库依赖于 UMD 库 ,请使用以下import语句:,不要使用指令/// <reference来声明对 UMD 库的依赖!
/// <reference types="moment" />
function getThing(): moment;
import * as someLib from "someLib";
1
2
3

# 知识小记❗️❗️❗️❗️

export default请注意,在 .d.ts 文件中使用需要esModuleInterop: true工作。如果您的项目中没有esModuleInterop: true,例如当您向Definitely Typed 提交 PR 时,则必须使用该export=语法。这种较旧的语法更难使用,但在任何地方都适用。下面是如何使用以下方式编写上面的示例export=:

使用 export default

export default function getArrayLength(arr: any[]): number;
export const maxInterval: 12;
1
2

使用 export=

declare function getArrayLength(arr: any[]): number;
declare namespace getArrayLength {
  declare const maxInterval: 12;
}
export = getArrayLength;
1
2
3
4
5

# export as namespace 可选的全局使用

您可以使用export as namespace声明您的模块将在 UMD 上下文中的全局范围内可用:

export as namespace moduleName;
1

参考如下声明文件示例


如果此模块是一个UMD模块,当在模块加载程序环境外部加载时,它会公开全局变量“myLib”,请在此处声明该全局变量。
否则删除下面声明

export as namespace myLib;


如果这个模块导出一个函数,则像下面这样声明
export function myFunction(a: string): string;
export function myOtherFunction(a: number): number;

您可以声明类型,这个类型可通过导入的方式使用
export interface SomeType {
  name: string;
  length: number;
  extras?: string[];
}

您可以使用let cont var 来声明模块的属性

export const myField: number;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 全局修改模块

全局修改模块在导入时会更改全局范围内的现有值,比如在原型上加新方法String.prototype.xx = x

如果全局修改模块是可调用或可构造的,则需要将此处的模式与模块类或模块函数模板文件中的模式相结合
比如扩展 String的原型上的方法
declare global {
  /*~ Here, declare things that go in the global namespace, or augment
   *~ existing declarations in the global namespace
   */
  interface String {
    fancyFormat(opts: StringFormatOptions): string;
  }
}

如果你的模块导出了类型或者值,则可以这么写
export interface StringFormatOptions {
  fancinessLevel: number;
}



如果你的模块什么也没导出则需要下面这样,如果导出的话,则需要删除他
export {};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22