浅谈 TypeScript - 模块

537 阅读3分钟

es2015 开始 JavaScript 有了自己的模块,TypeScript 也遵循了这样的定义,其实在 TypeScript 还有一个命名空间的概念,这样的概念应该说从历史遵循而来,上了年纪的前端程序员应该会对YUI有一些印象,当年的前端对于命名空间的运用,这是最出色的一款框架。不过,今天我们将讲一讲 TypeScript 中的模块,以及另外一些模块规范的第三方包,该如何在 TypeScript 中引用。

对于模块而言它自身是运行在一个局部的作用域中的,这一点非常重要,这也意味着在一个模块中的变量,函数,类等,除非你导出,外部程序是无法使用的,因此 TypeScript 也遵循了 importexport 的机制,反之如果一个文件内没有这两个关键字存在的话,那么它的内容将会被视为全局。

基础

导出一个常量:

export const D = "";

导入一个常量:

import { D } from "xx";

导出关键字和导入关键字都适用于重命名,如:

import { D as Dell } from "xx"

const C = "";
export { C as D }

我们也可以将所有的导出都导入到一个变量中,如:

export const A = "";
export const B = "";
import * as CONST from "xx";

每一个模块都可以使用一个默认的导出,如:

export default function reducers () {}
import reducers from "xx";

范例

在目前的 Web 前端工程中,大部分情况下我们都会在 JavaScript 引入样式,如:

import "./style.css"

当这样的范例有时候编译器并不能编译通过,也许我们可以定义一个通用的模块,如:

declare module "*.css";

当然,你也可以使用 require 语句来导入一个样式文件。

由于在我们的工作中,会引用到很多第三方的模块,由于历史的原因,可能很多第三方模块,用了 AMD 或者 commonjs,或者它们压根就没有 TypeScript 的声明文件,重要的是我们都可以定义一个自己的描述文件,起码可以让程序 Run 起来。

举例:

小明 在解析一个 url 时用了一个第三方包来完成,但是当他将第三方包引入到工程中时发现报错了,于是他自己定义了一个模块声明来处理这个错误,如:

declare module "url" {
  export function parse(urlStr: string) => string;
}

我们可以在工程中创建一个 typing 目录,编译器会自动的读取这个声明文件。

但是当工程中的错误,还是没有解决,因为它是一个 commonjs 的模块,由于 commonjs 中定义了 module.exportsexports,根据官方给出的建议是使用 import d = require("xxx"),但是对于有风格洁癖的人来说,这很不好看,但是我们可以从中遵循出来,由于 exports 的关系,以及现代编译器编译的规则,假设是导出了主模块,那么我们可以使用:

import g from "xx";

g.default()

假设,我们的 commonjs 是使用的 exports ,那么我们可以使用:

import * as g from "xx";

来解决这个问题。

于是 小明 很愉快的解决了错误,对于高效的程序员来说,老板又给 小明 涨薪了。

我们来看一看最终编译之后的代码:

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const url_1 = __importDefault(require("browser-used/lib/url"));
console.log(url_1.default);

是不是发现了很多很有趣的地方。