TypeScript$File-Module
P. JavaScript Module
JavaScript 模块的标准是 ES Module,使用的是 import / export 语法。
在 ES Module 出现之前,Node 的标准是 CommonJS,使用的是 require / module.exports 语法。
0. Module or not
在 TypeScript 看来,没有使用 import / export / top-level await 的文件是 script,不是 module。
如果想让一个文件变成 module,可以加一行 export {}。
1. ES Module imports and exports of TypeScript
1.1 import
JavaScript 的 import 语法就不说明了,TypeScript 特有的语法:
- normal import:
import { Cat, Dog } from "./animal.js"; // Cat and Dog are types - import type:
import type { Cat, Dog } from "./animal.js"; - inline type imports:
import { createCatName, type Cat, type Dog } from "./animal.js";
1.2 export
// @filename: animal.ts
export type Cat = { breed: string; yearOfBirth: number };
export interface Dog {
breeds: string[];
yearOfBirth: number;
}
// @filename: app.ts
import { Cat, Dog } from "./animal.js";
type Animals = Cat | Dog;
2. CommonJS Interop
CommonJS 的导出分为两种情况:
- 暴露出一个对象,每个属性都有明确的名字:
module.exports = { Banana } - 暴露对象的属性没有明确的名字:
module.exports = Melon对于第一种,正常的导入就行
import { Banana } from './banana'
const fs = require("fs")
import * as fs from "fs"
import { readFileSync } from "fs"
对于第二种情况,正常的导入会报错,需要使用 TypeScript 的特殊语法(配置项esModuleInterop 和 allowSyntheticDefaultImports 能阻止报错,但其他引入你的 TypeScript 项目也得开启这两个配置项):
import * as Melon from "./melon" // error
import Melon = require("./melon") // OK
3. Native ES module support
This means you can natively run code containing thing like import { Foo } from 'bar', use top-level await and more!
通过文件名的后缀能区分 native ES modules / CJS modules:
- Files with the
.mjsextension are treated as native ES modules - Files with the
.cjsextension are treated as CJS modules
区分普通的 .js 文件是什么类型——配置 package.json 的 "type":
"module": ES modules"commonjs": CommonJS
3.1 TypeScript ES modules
.mtsfiles are for TypeScript ES modules, and generate ES modules as output.ctsfiles are for TypeScript CJS modules, and generate CJS modules as output
4. Importing non-TS things
import img from "./file.png"
// error. Cannot find module './file.png' or its corresponding type declarations.
file.png is obviously not a TypeScript file — we just need to tell TypeScript that whenever we import a .png file, it should be treated as if it’s a JS module with a string value as its default export.
This can be accomplished through a module declaration as shown below:
// @filename: global.d.ts
declare module "*.png" {
const imgUrl: string
export default imgUrl
}
// @filename: component.ts
import img from "./file.png"