如何在npm TypeScript包中编写支持顶级await的工具脚本
问题描述
我正在开发TypeScript React项目,想自动化新组件的文件夹和文件创建流程——用TypeScript写工具脚本保证类型安全,依赖能通过npm轻松安装,还想用await语法(最好是顶级await)。希望尽量不修改主tsconfig.json,只对package.json的scripts和devDependencies做最小改动。
现有文件结构:
. ├── package.json ├── scripts │ └── createFile.ts ├── src │ └── components └── tsconfig.json
package.json内容:
{ "name": "utilscript", "version": "1.0.0", "scripts": { "create-file": "ts-node scripts/createFile.ts" }, "devDependencies": { "@types/node": "^18.15.5", "ts-node": "^10.9.1", "typescript": "^5.0.2" } }
主tsconfig.json内容:
{ "compilerOptions": { "target": "es2016", "module": "commonjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true }, "include": [ "src" ] }
scripts/createFile.ts内容:
import { writeFile, mkdir } from 'node:fs/promises' const componentName = 'Test' // 最终会改成命令行参数 await mkdir(`./src/components/${componentName}`) await writeFile(`./src/components/${componentName}/index.tsx`, '')
遇到的错误
- 执行
npm run create-file时,TS报错顶级await不允许:
scripts/createFile.ts:5:1 - error TS1378: Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', or 'nodenext', and the 'target' option is set to 'es2017' or higher. 5 await mkdir(`./src/components/${componentName}`) ~~~~~ scripts/createFile.ts:6:1 - error TS1378: Top-level 'await' expressions are only allowed when the 'module' option is set to 'es2022', 'esnext', 'system', 'node16', or 'nodenext', and the 'target' option is set to 'es2017' or higher. 6 await writeFile(`./src/components/${componentName}/index.tsx`, '') ~~~~~
- 把主
tsconfig.json的module改成esnext、target改成es2017后,执行命令出现模块错误:
(node:66146) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. (Use `node --trace-warnings ...` to show where the warning was created) /Users/rpmccarter/Documents/codes/misc/stackOverflow/utilScript/scripts/createFile.ts:1 import { writeFile, mkdir } from 'node:fs/promises'; ^^^^^^ SyntaxError: Cannot use import statement outside a module
- 在
package.json添加"type": "module"后,又出现文件扩展名错误:
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".ts" for /Users/rpmccarter/Documents/codes/misc/stackOverflow/utilScript/scripts/createFile.ts
解决方案
方案1:给ts-node指定临时编译参数(无需修改主tsconfig)
直接在package.json的scripts里给ts-node追加参数,临时覆盖编译配置以支持顶级await,同时处理ES模块兼容:
"scripts": { "create-file": "ts-node --esm --compiler-options '{\"module\":\"esnext\",\"target\":\"es2017\"}' scripts/createFile.ts" }
--esm:让ts-node以ES模块模式运行,避免import语法报错--compiler-options:临时设置满足顶级await要求的编译选项,不改动主tsconfig
方案2:给scripts文件夹单独配置tsconfig
如果觉得命令行参数太长,可在scripts目录下新建tsconfig.scripts.json:
{ "extends": "../tsconfig.json", "compilerOptions": { "module": "esnext", "target": "es2017" }, "include": ["."] }
然后修改package.json的scripts:
"scripts": { "create-file": "ts-node --project scripts/tsconfig.scripts.json --esm scripts/createFile.ts" }
这种方式既复用主配置,又单独给脚本设置所需编译选项,不影响主项目的tsconfig。
方案3:用tsx替代ts-node(最简洁)
tsx是一个无需额外配置就能直接运行TS/TSX文件的工具,天然支持ES模块和顶级await:
- 安装tsx:
npm install -D tsx
- 修改
package.json的scripts:
"scripts": { "create-file": "tsx scripts/createFile.ts" }
无需修改任何tsconfig,tsx会自动处理所有编译需求,非常适合写工具脚本。
额外提示
当前脚本的mkdir遇到已存在的文件夹会报错,可添加{ recursive: true }参数避免:
await mkdir(`./src/components/${componentName}`, { recursive: true })
内容的提问来源于stack exchange,提问作者rpm
相关产品推荐
相关产品推荐

