如何用TypeScript编写兼容Node.js与浏览器的可复用类?
嗨!既然你已经熟悉 TypeScript 和 JavaScript,但刚接触 Node.js,那咱们一步步来搞定如何编写能同时在 Node.js 和浏览器环境复用的代码,尤其是你提到的那个类。下面是一套清晰的方案:
1. 编写与环境无关的 TypeScript 类
首先,核心类要避免直接依赖 Node.js 专属 API(比如 fs、process)或浏览器专属 API(比如 window、document)。如果确实需要环境相关功能,通过条件判断兼容即可。
示例代码 src/MyAbstractClass.ts:
export abstract class MyAbstractClass { protected name: string; constructor(name: string) { this.name = name; } abstract doSomething(): void; // 通用方法,不依赖任何环境 greet(): string { return `Hello, ${this.name}!`; } // 兼容环境的逻辑示例 getEnvironment(): string { if (typeof window !== 'undefined') { return 'browser'; } else if (typeof process !== 'undefined' && process.versions.node) { return 'node'; } return 'unknown'; } }
2. 配置 TypeScript 生成双环境代码
我们需要让 TypeScript 分别生成适合 Node.js 的 CommonJS 模块和适合浏览器的 ES 模块。创建两个配置文件:
针对 Node.js 的 tsconfig.node.json
{ "compilerOptions": { "target": "ES2020", "module": "CommonJS", "outDir": "./dist/node", "declaration": true, "strict": true, "esModuleInterop": true }, "include": ["src/**/*"] }
针对浏览器的 tsconfig.browser.json
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "outDir": "./dist/browser", "declaration": true, "strict": true, "lib": ["ES2020", "DOM"] // 引入浏览器相关标准库 }, "include": ["src/**/*"] }
在 package.json 中添加构建脚本:
{ "scripts": { "build": "tsc -p tsconfig.node.json && tsc -p tsconfig.browser.json" } }
运行 npm run build 后,dist/node 和 dist/browser 目录会生成对应环境的 JS 文件和类型定义。
3. 让 Node.js 自动识别模块(可选)
在 package.json 中添加条件导出,Node.js 会自动匹配对应环境的模块:
{ "exports": { ".": { "node": "./dist/node/MyAbstractClass.js", "default": "./dist/browser/MyAbstractClass.js" } }, "types": "./dist/node/MyAbstractClass.d.ts" }
4. 在浏览器中使用
方式一:ES 模块引入(现代浏览器推荐)
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8" /> </head> <body> <script type="module"> import { MyAbstractClass } from './dist/browser/MyAbstractClass.js'; // 实现抽象类 class MyConcreteClass extends MyAbstractClass { doSomething() { console.log(`Browser is doing something for ${this.name}`); } } const instance = new MyConcreteClass('Silas'); console.log(instance.greet()); // 输出 Hello, Silas! console.log(instance.getEnvironment()); // 输出 browser </script> </body> </html>
方式二:全局变量引入(兼容旧浏览器)
用 esbuild 打包成 IIFE 格式(类会挂载到全局):
npx esbuild ./src/MyAbstractClass.ts --bundle --outfile=./js/myabstractclass.js --format=iife --global-name=MyLib
然后在 HTML 中引入:
<script type="text/javascript" src="/js/myabstractclass.js"></script> <script> class MyConcreteClass extends MyLib.MyAbstractClass { doSomething() { console.log(`Doing something in browser!`); } } const instance = new MyConcreteClass('Test'); console.log(instance.greet()); </script>
5. 在 Node.js 中测试
创建 test-node.js:
const { MyAbstractClass } = require('./dist/node/MyAbstractClass.js'); class MyConcreteClass extends MyAbstractClass { doSomething() { console.log(`Node.js is doing something for ${this.name}`); } } const instance = new MyConcreteClass('Silas'); console.log(instance.greet()); // 输出 Hello, Silas! console.log(instance.getEnvironment()); // 输出 node instance.doSomething();
运行 node test-node.js 即可看到结果。
内容的提问来源于stack exchange,提问作者Silas
相关产品推荐
相关产品推荐

