科技微讯

Typescript 引入模块的三种写法

Typescript 是 javascript 的超集,js 有的功能 ts 也有,这意味着 ts 在引入一个模块时,支持 CommonJS、ES module 两种引入方法。作为超集,ts 还支持一些独有的引入语法。

const...require...

const path = require("path");

如果提示 require 错误,可能是因为没有安装@types/node

import...from...

import path from "path";

这样可能会报错:

This module is declared with 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.

所以需要在 tsconfig.json 中设置 compilerOptions.esModuleInteroptrue

再比如 fs

import fs from "fs";

可能会报错:

Module '"fs"' has no default export.

需要改为:

import * as fs from "fs";

import...require...

从上面的报错可知 path 是通过 export = 导出的,如果不想把 compilerOptions.esModuleInterop 设为 true,还可以这样写:

import path = require("path");

import = require() 就是 ts 的独有语法,起码在 Typescript 1.0 就支持了。

import type

值得一提的是,ts 在 import 一个 type 时,建议使用 import type,很明显这也是 Typescript 的独有语法。

// Re-using the same import
import { APIResponseType } from "./api";
// Explicitly use import type
import type { APIResponseType } from "./api";
// Explicitly pull out a value (getResponse) and a type (APIResponseType)
import { getResponse, type APIResponseType } from "./api";

用 import 还是 require

Node.js 同时支持 CommonJS、ES Module,浏览器只支持 ES Module,那是不是意味着 Gatsby.js、Next.js 这些框架不能写 require 呢?非也。无论项目是不是用 ts 写,Gatsby.js、Next.js 可以在页面或组件中同时使用 requireimport,甚至可以在同一个组件混着用这两种方法。因为开发者写的代码并不是直接运行在 Node.js 或浏览器中,而是都会被 compiler 转换后再执行。

同理,ts 写的代码也不是直接运行在 Node.js 或浏览器中,.ts.tsx 会被 compiler 先转换为标准的 js 代码,这时 import 可以被转换为 require,或者反过来。

tsconfig.json 有一个 compilerOptions.module 字段,设置为 commonjs 时,Typescript 官方 compiler tsc 会把 import 转换为 require,设置为 ESNextES2020 等值时,import 会被保留。tsc 似乎不会把 require 转换为 import,这需要使用 babel、swc 等其他 compiler。

在 Next.js 中,compilerOptions.jsx 的值被设置为 preserve,这样 tsc 只是把 .tsx 转换为 .jsx,后续 .jsx 转换为 .js 就交给 swc 或 babel。swc 既可以把代码转换为 CommonJS,也可以转换为 ES6 module。babel 也是。在 swc、babel 的支持下,import 不仅可以用于 js 文件的引入,还可用来引入 image 等文件。

位于 Gatsby.js 或 Next.js 根目录的配置文件例如 next.config.js 由于不会被 babel 或 swc compile,默认只能用 require,这也是 Next.js 不支持 next.config.ts 的原因。从 Next.js 12 开始 next.config.js 可以改为 next.config.mjs,这样就能用 import 了,因为 .mjs 后缀把这个文件从一个 CommonJS 模块变成了 ES6 模块。

虽然在 ts 中既可以用 require 也可以用 import 甚至还能混着用,但现在人们写 ts 通常用 import,主要原因可能是 import 毕竟是 ECMAScript 标准内的东西,而且 ts 从 2012 年刚发布时就开始使用 import 了,ES6 module 可能也是受到 Typescript 的启发吧?另外 ts 的独有写法 import typeimport=require() 也用 import,为了让代码统一风格,一律用 import 应该是比较好的做法。关于用 import 还是 require,可以看看 stackoverflow 的一个帖子

ts-node

ts-node 可以用来直接执行 .ts 文件,它的工作原理是在后台把 .ts 转换为 .js,再调用 Node.js 去执行。在 npm script 中使用 ts-node,ts-node 默认会使用 tsconfig.jsonpackage.json 的配置,如果 compilerOptions.module 被设置为 esnext,则 ts-node 会把 .ts 转换为 ES6 module 的 .js,接下来用 node 去执行这个 .js 文件,有三种情况:

compilerOptions.module 如果设置为 commonjs,那 ts-node 可以直接执行 .ts 文件。ts-node 也可以通过 --skipProject 参数忽略 tsconfig.json 配置,直接执行 .ts 文件,它会默认把 .ts 转换为 commonjs 的 .js,Node.js 默认支持 commonjs,所以不需要任何其他设置。

Next.js 的配置文件不支持使用 Typescript,但 jest 的配置文件 jest.config.ts 可以用 Typescript 写,但需要额外安装 ts-node。


相关笔记:

相关阅读:

暂无评论