EggJS 项目中使用 TypeScript 的完整指南

EggJS 项目中使用 TypeScript 的完整指南

egg Born to build better enterprise frameworks and apps with Node.js & Koa egg 项目地址: https://gitcode.com/gh_mirrors/eg/egg

前言

TypeScript 作为 JavaScript 的超集,通过静态类型检查、智能提示和友好的 IDE 支持,为大型企业级应用开发带来了显著优势。本文将详细介绍如何在 EggJS 框架中集成和使用 TypeScript,帮助开发者提升开发效率和代码质量。

为什么选择 TypeScript

TypeScript 为 JavaScript 带来了类型系统,主要优势包括:

  1. 静态类型检查:在编译阶段就能发现潜在的类型错误
  2. 智能提示:IDE 能提供更准确的代码补全和文档提示
  3. 更好的可维护性:类型注解使代码更易于理解和维护
  4. 渐进式采用:可以逐步将现有 JavaScript 项目迁移到 TypeScript

快速开始

初始化项目

使用以下命令快速创建一个 TypeScript 版本的 EggJS 项目:

mkdir showcase && cd showcase
npm init egg --type=ts
npm i
npm run dev

这个命令会创建一个简单的 TypeScript 示例项目,包含基本的控制器、服务和路由配置。

项目结构

TypeScript 项目结构与常规 EggJS 项目类似,主要区别在于:

  • 文件后缀使用 .ts 而不是 .js
  • 新增 typings 目录存放类型定义文件
  • 需要 tsconfig.jsontslint.json 配置文件

典型目录结构如下:

showcase
├── app
│   ├── controller
│   │   └── home.ts
│   ├── service
│   │   └── news.ts
│   └── router.ts
├── config
│   ├── config.default.ts
│   ├── config.local.ts
│   ├── config.prod.ts
│   └── plugin.ts
├── test
│   └── **/*.test.ts
├── typings
│   └── **/*.d.ts
├── README.md
├── package.json
├── tsconfig.json
└── tslint.json

核心概念实现

控制器(Controller)

控制器示例:

import { Controller } from 'egg';

export default class HomeController extends Controller {
  public async index() {
    const { ctx, service } = this;
    const page = ctx.query.page;
    const result = await service.news.list(page);
    await ctx.render('home.tpl', result);
  }
}

路由(Router)

路由配置示例:

import { Application } from 'egg';

export default (app: Application) => {
  const { router, controller } = app;
  router.get('/', controller.home.index);
};

服务(Service)

服务层示例:

import { Service } from 'egg';

export default class NewsService extends Service {
  public async list(page?: number): Promise<NewsItem[]> {
    return [];
  }
}

export interface NewsItem {
  id: number;
  title: string;
}

中间件(Middleware)

中间件实现示例:

import { Context } from 'egg';

export default function fooMiddleware() {
  return async (ctx: Context, next: any) => {
    await next();
  };
}

配置(Config)

配置管理是 TypeScript 集成中最复杂的部分,需要处理:

  1. 控制器和服务中的多层智能提示配置
  2. 配置合并时的类型提示
  3. 自定义配置的类型扩展

配置示例:

import { EggAppInfo, EggAppConfig, PowerPartial } from 'egg';

export default (appInfo: EggAppInfo) => {
  const config = {} as PowerPartial<EggAppConfig>;

  config.keys = appInfo.name + '123456';
  config.view = {
    defaultViewEngine: 'nunjucks',
    mapping: {
      '.tpl': 'nunjucks',
    },
  };

  const bizConfig = {
    news: {
      pageSize: 30,
      serverUrl: 'https://hacker-news.firebaseio.com/v0',
    },
  };

  return {
    ...(config as {}),
    ...bizConfig,
  };
};

开发工具链

ts-node 集成

egg-bin 内置了 ts-node 支持,开发时自动加载和编译 .ts 文件。只需在 package.json 中配置:

{
  "egg": {
    "typescript": true
  }
}

egg-ts-helper

由于 EggJS 的自动加载机制,TypeScript 无法静态分析依赖关系。我们使用 egg-ts-helper 工具自动生成类型定义文件:

{
  "egg": {
    "declarations": true
  },
  "scripts": {
    "dev": "egg-bin dev",
    "clean": "ets clean"
  }
}

该工具会自动分析项目并生成 typings/{app,config}/ 下的类型定义文件,开发者不应手动修改这些文件。

测试与调试

单元测试

测试文件示例:

import assert from 'assert';
import { Context } from 'egg';
import { app } from 'egg-mock/bootstrap';

describe('test/app/service/news.test.js', () => {
  let ctx: Context;

  before(async () => {
    ctx = app.mockContext();
  });

  it('list()', async () => {
    const list = await ctx.service.news.list();
    assert(list.length === 30);
  });
});

调试配置

调试配置与常规 JavaScript 项目类似,通过 sourcemap 可以准确定位到 TypeScript 源代码:

{
  "scripts": {
    "debug": "egg-bin debug",
    "debug-test": "npm run test-local -- --inspect"
  }
}

生产部署

构建流程

生产环境建议将 TypeScript 编译为 JavaScript 再运行:

{
  "scripts": {
    "start": "egg-scripts start --title=egg-server-showcase",
    "tsc": "ets && tsc -p tsconfig.json",
    "ci": "npm run lint && npm run cov && npm run tsc"
  }
}

错误堆栈

构建时启用 inlineSourceMap 确保线上错误能映射到 TypeScript 源码:

{
  "compilerOptions": {
    "inlineSourceMap": true
  }
}

常见问题解答

生产环境 ts 文件未加载

npm start 使用 egg-scripts 运行,而 ts-node 只集成在 egg-bin 中。生产环境建议先编译再运行:

npm run tsc
npm start

插件对象未加载类型

可能原因:

  1. 插件缺少类型定义:需要按规范为插件添加 index.d.ts
  2. 插件有类型定义但未导入:需要显式导入插件类型声明

临时解决方案:

// typings/index.d.ts
import 'egg';

declare module 'egg' {
  interface Application {
    dashboard: any;
  }
}

tsconfig.json 中 paths 无效

tsc 不会转换 import 路径,运行时需要额外工具处理路径映射。建议使用模块别名工具如 module-alias

总结

本文详细介绍了在 EggJS 项目中使用 TypeScript 的完整方案,包括项目结构、核心概念实现、开发工具链、测试调试和生产部署等方面。通过合理配置和工具支持,可以在 EggJS 项目中充分发挥 TypeScript 的优势,提升开发体验和代码质量。

egg Born to build better enterprise frameworks and apps with Node.js & Koa egg 项目地址: https://gitcode.com/gh_mirrors/eg/egg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平钰垚Zebediah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值