任何声明(例如变量、函数、类、类型别名或套接字)也可以通过添加 export 关键字来导入。
验证.ts
export interface StringValidator {
isAcceptable(s: string): boolean;
}
ZipCodeValidator.ts
export const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
导入句子
导入句子很方便,因为我们可能需要重命名导入的部分,所以前面的例子可以这样重写:
class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
export { ZipCodeValidator };
export { ZipCodeValidator as mainValidator };
重新进口
我们经常扩展其他模块,但只导入该模块的一部分。 重新导入函数不会导出该模块或在当前模块中定义新的局部变量。
ParseIntBasedZipCodeValidator.ts
export class ParseIntBasedZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && parseInt(s).toString() === s;
}
}
// 导出原先的验证器但做了重命名
export {ZipCodeValidator as RegExpBasedZipCodeValidator} from "./ZipCodeValidator";
或者一个模块可以包装多个模块,通过这样的句型:export*from“module”将它们导入的内容组合起来。
AllValidators.ts
export * from "./StringValidator"; // exports interface StringValidator
export * from "./LettersOnlyValidator"; // exports class LettersOnlyValidator
export * from "./ZipCodeValidator"; // exports class ZipCodeValidator
出口
导出模块与导入模块一样简单。 您可以使用以下导入方法之一导出其他模块中导入的内容。
导出模块中的导入
import { ZipCodeValidator } from "./ZipCodeValidator";
let myValidator = new ZipCodeValidator();
导出内容可以重命名
import { ZipCodeValidator as ZCV } from "./ZipCodeValidator";
let myValidator = new ZCV();
将整个模块导出到变量并通过它访问模块的导入部分
import * as validator from "./ZipCodeValidator";
let myValidator = new validator.ZipCodeValidator();
导出的模块有副作用
尽管不推荐typescript 导入json,但某些模块会设置一些全局状态供其他模块使用。 这种模块可能没有任何导入,或者用户可能根本不注意它的导入。 使用以下方法导出此类模块:
import "./my-module.js";
默认导入
每个模块都可以有一个默认导入。 默认导入用default关键字标记; 并且一个模块只能有一个默认导入。 需要使用特殊的导出方法来导出默认导入。
默认导入非常方便。 例如,像 JQuery 这样的泛型可能默认导入 jQuery 或 $,但我们基本上也会导入具有相同名称 jQuery 或 $ 的 jQuery。
JQuery.d.ts
declare let $: JQuery;
export default $;
应用程序.ts
import $ from "JQuery";
$("button.continue").html( "Next Step..." );
类和函数声明可以直接标记为默认导入。 默认情况下标记为导入的类和函数的名称可以省略。
ZipCodeValidator.ts
export default class ZipCodeValidator {
static numberRegexp = /^[0-9]+$/;
isAcceptable(s: string) {
return s.length === 5 && ZipCodeValidator.numberRegexp.test(s);
}
}
测试.ts
import validator from "./ZipCodeValidator";
let myValidator = new validator();
或者
静态邮政编码验证器.ts
const numberRegexp = /^[0-9]+$/;
export default function (s: string) {
return s.length === 5 && numberRegexp.test(s);
}
测试.ts
import validate from "./StaticZipCodeValidator";
let strings = ["Hello", "98052", "101"];
// Use function validate
strings.forEach(s => {
console.log(`"${s}" ${validate(s) ? " matches" : " does not match"}`);
});
默认导入也可以是一个值
OneTwoThree.ts
export default "123";
日志.ts
import num from "./OneTwoThree";
console.log(num); // "123"
导出=和导入=require()
CommonJS 和 AMD 环境都有一个导出变量,其中包含模块的所有导入内容。
CommonJS 和 AMD 的导出都可以参数化为对象。 在这些情况下,它的功能类似于es6句型中的default import,即exportdefault句型。 好像有类似的功能,exportdefault句型不兼容CommonJS和AMD导出。
为了支持 CommonJS 和 AMD 导出,TypeScript 提供了 export= 句子模式。
export= 语法定义模块的导入对象。 这里的对象一词指的是类、套接字、命名空间、函数或枚举。
如果使用export=导入模块,则必须使用TypeScript的特定语法importmodule=require(“module”)来导出模块。
ZipCodeValidator.ts
let numberRegexp = /^[0-9]+$/;
class ZipCodeValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
export = ZipCodeValidator;
测试.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" }`);
});
生成模块代码
根据编译时指定的模块目标参数,编译器将为 Node.js(CommonJS)、Require.js(AMD)、UMD、SystemJS 或 (ES6) 模块加载系统生成相应的代码。 要了解生成代码中define、require、register的含义,请参考相应模块加载器的文档。
以下示例说明了导出和导入语句中使用的名称如何转换为相应的模块加载器代码。
简单模块.ts
import m = require("mod");
export let t = m.something + 1;
AMD/RequireJSSimpleModule.js
define(["require", "exports", "./mod"], function (require, exports, mod_1) {
exports.t = mod_1.something + 1;
});
CommonJS/NodeSimpleModule.js
let mod_1 = require("./mod");
exports.t = mod_1.something + 1;
UMDSimpleModule.js
(function (factory) {
if (typeof module === "object" && typeof module.exports === "object") {
let v = factory(require, exports); if (v !== undefined) module.exports = v;
}
else if (typeof define === "function" && define.amd) {
define(["require", "exports", "./mod"], factory);
}
})(function (require, exports) {
let mod_1 = require("./mod");
exports.t = mod_1.something + 1;
});
系统简单模块.js
System.register(["./mod"], function(exports_1) {
let mod_1;
let t;
return {
setters:[
function (mod_1_1) {
mod_1 = mod_1_1;
}],
execute: function() {
exports_1("t", t = mod_1.something + 1);
}
}
});
NativeECMAScript2015modulesSimpleModule.js
import { something } from "./mod";
export let t = something + 1;
简单的例子
我们来梳理一下上面的验证器实现。 每个模块只有一个命名导入。
为了编译typescript 导入json,我们必须在命令行上指定一个模块目标。 对于 Node.js,请使用 --modulecommonjs; 对于 Require.js,请使用 --moduleamd。 例如:
tsc --module commonjs Test.ts
编译完成后,每个模块都会生成一个单独的.js文件。 例如,如果使用了reference标签,编译器就会根据import语句编译出相应的文件。
验证.ts
export interface StringValidator {
isAcceptable(s: string): boolean;
}
LettersOnlyValidator.ts
import { StringValidator } from "./Validation";
const lettersRegexp = /^[A-Za-z]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
ZipCodeValidator.ts
import { StringValidator } from "./Validation";
const numberRegexp = /^[0-9]+$/;
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
测试.ts
import { StringValidator } from "./Validation";
import { ZipCodeValidator } from "./ZipCodeValidator";
import { LettersOnlyValidator } from "./LettersOnlyValidator";
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: StringValidator; } = {};
validators["ZIP code"] = new ZipCodeValidator();
validators["Letters only"] = new LettersOnlyValidator();
// Show whether each string passed each validator
strings.forEach(s => {
for (let name in validators) {
console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
}
});
可选模块加载及其他中间加载场景
有时,您只想在特定条件下加载模块。 在TypeScript中,使用以下方法来实现这种以及其他中间加载场景,我们可以直接调用模块加载器并确保类型完整。
编译器检查每个模块是否将在生成的 JavaScript 中使用。 如果模块标识符仅在类型注释中使用而根本不在表达式中使用,则不会生成任何代码来需要该模块。 省略未使用的引用对于性能非常有益,并且提供了选择性加载模块的能力。
这些模式的核心是 importid=require("...") 语句,它允许我们访问模块导入的类型。 模块加载器将被动态调用(通过 require),如下面的 if 块所示。 它利用了省略引用的优化,因此仅在需要时加载模块。 为了使该模块正常工作,需要注意的是, import 定义的标识符只能在表示类型的地方使用(而不是在将其转换为 JavaScript 的地方)。
为了确保类型安全,我们可以使用 typeof 关键字。 typeof 关键字在表示类型的地方使用时,将产生一个类型值,此处表示模块的类型。
示例:Node.js 中的动态模块加载
declare function require(moduleName: string): any;
import { ZipCodeValidator as Zip } from "./ZipCodeValidator";
if (needZipValidation) {
let ZipCodeValidator: typeof Zip = require("./ZipCodeValidator");
let validator = new ZipCodeValidator();
if (validator.isAcceptable("...")) { /* ... */ }
}
示例:require.js 中的动态模块加载
declare function require(moduleNames: string[], onLoad: (...args: any[]) => void): void;
import * as Zip from "./ZipCodeValidator";
if (needZipValidation) {
require(["./ZipCodeValidator"], (ZipCodeValidator: typeof Zip) => {
let validator = new ZipCodeValidator.ZipCodeValidator();
if (validator.isAcceptable("...")) { /* ... */ }
});
}
示例:System.js 中的动态模块加载
declare const System: any;
import { ZipCodeValidator as Zip } from "./ZipCodeValidator";
if (needZipValidation) {
System.import("./ZipCodeValidator").then((ZipCodeValidator: typeof Zip) => {
var x = new ZipCodeValidator();
if (x.isAcceptable("...")) { /* ... */ }
});
}
使用其他 JavaScript 库
为了描述不是用 TypeScript 编写的泛型类型,我们需要声明泛型类型公开的 API。
我们称其为声明,因为它不是“外部程序”的具体实现。 它们通常在 .d.ts 文件中定义。 如果您熟悉 C/C++,您可以将它们视为 .h 文件。 让我们看一些反例。
外部模块
Node.js 中的大部分工作都是通过加载一个或多个模块来完成的。 我们可以使用顶部导出声明为每个模块定义一个 .d.ts 文件,但最好将其写在一个大的 .d.ts 文件中。 我们使用类似于构造外部命名空间的方法,这里使用 module 关键字,并用冒号将名称括起来,以方便将来导入。 例如:
node.d.ts(简化摘录)
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;
}
现在我们可以 ///node.d.ts 并使用 importurl=require("url"); 或 import*asURLfrom"url" 加载模块。
///
import * as URL from "url";
let myUrl = URL.parse("http://www.typescriptlang.org");
外部模块缩写
如果您不想在使用新模块之前花时间编译声明,则可以缩写声明,以便可以快速使用它。
声明.d.ts
declare module "hot-new-module";
缩写模块中的所有导入类型均为any。
import x, {y} from "hot-new-module";
x(y);