relative 和 non-relative import
Relative Import以/, ./或../為開頭. 如
import Entry from "./components/Entry";
import { DefaultHeaders } from "../constants/http";
import "/mod";
所有其他的都是為non-relative import, 如:
import * as $ from "jquery";
import { Component } from "@angular/core";
relative import引入相對于當前文件路徑的文件, 且無法引入ambient module declarations. 使用relative import來引入你自己實現的文件.
non-relative import引入相對于baseUrl路徑, 或者存在于路徑映射(Path Mapping)中的文件, 可以引入ambient module declarations. 使用non-relative import來引入外部依賴.
模塊解析策略
有兩種策略: Node或Classic. 通過--moduleResolution來指定策略. 對于--module AMD | System | ES2015來說, 默認是Classic.
Classic (經典策略)
這曾是TypeScript的默認路徑解析策略. 現在它主要是為了維護向后兼容性了.
對于relative import, 在文件/root/src/folder/A.ts中`import { b } from "./moduleB", 會進行如下查找:
/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts
對于non-relative import, 查找過程會從當前文件沿著文檔樹向上查找. 在文件/root/src/folder/A.ts中import { b } from "moduleB", 會進行如下查找:
/root/src/folder/moduleB.ts/root/src/folder/moduleB.d.ts/root/src/moduleB.ts/root/src/moduleB.d.ts/root/moduleB.ts/root/moduleB.d.ts/moduleB.ts/moduleB.d.ts
Node策略
這個策略模仿Node.js的模塊解析策略. Node.js的完整解析算法見這里.
Node.js如何解析模塊
Node.js中調用require方法來引入模塊.
require的路徑為相對路徑
文件/root/src/moduleA.js中通過import var x = require("./moduleB");引入模塊, 查找過程如下:
- 文件
/root/src/moduleB.js - 文件夾
/root/src/moduleB, 且其中有package.json文件指定了"main"模塊. 如/root/src/moduleB/package.json中有{ "main": "lib/mainModule.js" }, 那么Node.js會引入/root/src/moduleB/lib/mainModule.js - 文件夾
/root/src/moduleB, 且其中有index.js. 這是默認的"main"模塊.
require的路徑為絕對路徑
Node會從node_modules文件夾中尋找模塊. node_modules可能是在源文件當前目錄中, 也可能是在文件樹的上層. Node會沿著文件樹逐層向上尋找node_modules中的模塊.
文件/root/src/moduleA.js通過import var x = require("moduleB");引入模塊, 查找過程如下:
/root/src/node_modules/moduleB.js-
/root/src/node_modules/moduleB/package.json(if it specifies a"main"property) /root/src/node_modules/moduleB/index.js/root/node_modules/moduleB.js-
/root/node_modules/moduleB/package.json (if it specifies a"main"` property) /root/node_modules/moduleB/index.js/node_modules/moduleB.js-
/node_modules/moduleB/package.json(if it specifies a"main"property) /node_modules/moduleB/index.js
TypeScript如何解析模塊
TypeScript模仿了Node的解析策略, 不過針對的是.ts, .tsx和.d.ts文件, 而且package.json中用"types"對應于Node中的"main".
相對路徑
文件/root/src/moduleA.ts中引入import { b } from "./moduleB", 查找過程如下:
/root/src/moduleB.ts/root/src/moduleB.tsx/root/src/moduleB.d.ts-
/root/src/moduleB/package.json(if it specifies a"types"property) /root/src/moduleB/index.ts/root/src/moduleB/index.tsx/root/src/moduleB/index.d.ts
絕對路徑
文件/root/src/moduleA.ts中引入import { b } from "moduleB", 查找過程如下:
/root/src/node_modules/moduleB.ts/root/src/node_modules/moduleB.tsx/root/src/node_modules/moduleB.d.ts-
/root/src/node_modules/moduleB/package.json(if it specifies a"types"property) /root/src/node_modules/moduleB/index.ts/root/src/node_modules/moduleB/index.tsx/root/src/node_modules/moduleB/index.d.ts/root/node_modules/moduleB.ts/root/node_modules/moduleB.tsx/root/node_modules/moduleB.d.ts-
/root/node_modules/moduleB/package.json(if it specifies a"types"property) /root/node_modules/moduleB/index.ts/root/node_modules/moduleB/index.tsx/root/node_modules/moduleB/index.d.ts/node_modules/moduleB.ts/node_modules/moduleB.tsx/node_modules/moduleB.d.ts-
/node_modules/moduleB/package.json(if it specifies a"types"property) /node_modules/moduleB/index.ts/node_modules/moduleB/index.tsx/node_modules/moduleB/index.d.ts
模塊解析參數
通常, 項目中都會通過一系列的構建程序將源目錄中的文件, 打包/壓縮到目標目錄中. 這個過程可能導致文件名或目錄結構發(fā)生變化. 因此TypeScript編譯器有如下幾個參數應對這種變化.
Base URL
AMD模塊加載器, 如requireJS, 常使用baseUrl. 源文件可以在多個目錄中, 但目標文件會被放到同一個目錄中.
所有non-relative import都相對于baseUrl.
baseUrl的值可以是:
- baseUrl的命令行參數 (如果參數為相對路徑, 則該參數相對于當前路徑)
-
tsconfig.json中的baseUrl(如果參數為相對路徑, 則該參數相對于tsconfig.json的目錄)
Path Mapping (路徑映射)
你還可以使用tsconfig.json中的"paths"屬性, 定義Path Mapping. 如:
{
"compilerOptions": {
"baseUrl": ".", // This must be specified if "paths" is.
"paths": {
"jquery": ["node_modules/jquery/dist/jquery"] // This mapping is relative to "baseUrl"
}
}
}
注意Path Mapping是相對于baseUrl的.
"paths"可以用來實現路徑回退(Fallback)查找. 舉個例子.
projectRoot
├── folder1
│ ├── file1.ts (imports 'folder1/file2' and 'folder2/file3')
│ └── file2.ts
├── generated
│ ├── folder1
│ └── folder2
│ └── file3.ts
└── tsconfig.json
tsconfig.json內容如下
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": [
"*",
"generated/*"
]
}
}
}
這個配置讓編譯器對滿足模式"*"(即所有文件)的模塊引用, 進行如下查找:
-
"*": meaning the same name unchanged, so map<moduleName>=><baseUrl>/<moduleName> -
"generated/*"meaning the module name with an appended prefix“generated”, so map<moduleName>=><baseUrl>/generated/<moduleName>
所以, 對于file1.ts中的兩個引用:
-
import ‘folder1/file2’-
"*"捕獲文件名folder1/file2 - 嘗試第一種替換, 即:
"*"=>folder1/file2 - 得到的是絕對路徑, 將其與
baseUrl結合, 得到projectRoot/folder1/file2.ts - 文件找到, 結束.
-
-
import ‘folder2/file3’-
"*"捕獲文件名folder2/file3 - 嘗試第一種替換, 即:
"*"=>folder2/file3 - 得到的是絕對路徑, 將其與
baseUrl結合, 得到projectRoot/folder2/file3.ts - 文件不存在, 嘗試第二種替換
"generated/*"=>generated/folder2/file3 - 得到的是絕對路徑, 將其與
baseUrl結合, 得到projectRoot/generated/folder2/file3.ts - 文件找到, 結束.
-
import后面的花括號
export分為兩種, Named Export(有名導出)和Default Export(默認導出). 花括號是用于Named Export的.
Named Export
// module.ts
export function A() { ... };
export function B() { ... };
// app.ts
import { A, B as BB } from 'module.ts';
其中, 函數A和B是Named Export模式, 導入時需要加花括號, 而且可以使用as改名.
Default Export
// module.ts
export default function C () { ... };
// app.ts
import myFunc from 'module';
// or
import { default as myFunc } from 'module';
函數C以default方式導出, 引入的時候不用加花括號, myFunc即為C.
其實default導出也是一種Named Export, 只不過它導出的變量被加了默認的名字default, 所以app.ts中的兩句話效果一樣.
export =和import = require()
CommonJS 和 AMD 都有exports對象的概念, exports對象包含了所有導出的內容. 它們也都支持將exports對象替換為自己指定的一個對象/函數/變量等.
相應地, Typescript使用export =, 導出的內容可以是class, interface, namespace, function或者enum.
使用export =時必須相應地使用import module = require("module").
// module.ts
class A { ... }
export = A;
// app.ts
import A = requrie("module");
import * as X from "XXX"是什么意思
// pet.ts
export class Dog { ... }
export class Cat { ... }
// app.ts
import * as Pet from "./pet.ts";
let x = new Pet.Dog();
可以看到, import * as X from "XXX"的作用就是從"XXX"文件中, 引入所有導出的內容作為X的屬性.
與import X = require("XXX")作用相同.
ambient module declarations
var x = require VS import x from
在Node.js (CommonJS)中使用 var x = require("XXX"), 其中var也可以用const等修飾詞替換. 與之配套的是module.exports和exports.
exports.A = function() {...}
module.exports.A = function() {...}
module.exports = { ... }
ES6采用import x from的形式, 與之配套的是export:
export function A() { ... }
export = { ... }
var x = require和import x = require的區(qū)別?
我現在項目中??吹?code>import x = require.