当前位置: 首页 > news >正文

集成koa2+ts+typeorm记录

集成koa2+ts+typeorm记录

  • 1 使用koa-generator创建基础结构
  • 2 转成ts并使用ES模块
  • 3 引入typeorm

1 使用koa-generator创建基础结构

koa的官网?

提前安装koa脚手架

npm install -g koa-generator

创建项目(使用ejs引擎)

koa2 project-name -e

导入依赖

pnpm i

2 转成ts并使用ES模块

安装必要依赖

npm install typescript ts-node @types/node -D

根据实际使用的中间件添加ts声明

pnpm i @types/koa @types/koa-bodyparser @types/koa-json
@types/koa-router -D

生成tsconfig.json

npx tsc --init

内容如下

{// TypeScript 配置文件,用于配置 TypeScript 编译器选项// 详细信息请访问 https://aka.ms/tsconfig"compilerOptions": {// 文件布局配置"rootDir": "./", // 指定 TypeScript 源代码根目录"outDir": "./dist", // 指定编译后 JavaScript 文件的输出目录// 编译环境设置// 模块系统设置,使用 nodenext 支持 Node.js 的 ES 模块// 详细信息请参考 https://aka.ms/tsconfig/module"module": "nodenext","moduleResolution": "nodenext",// 目标 JavaScript 版本,编译为最新的 ES 标准"target": "esnext",// 指定运行环境为 Node.js,包含 ES 最新特性库"lib": ["esnext"],// 包含 Node.js 的类型定义"types": ["node"],// 需要安装 @types/node 包提供 Node.js API 的类型定义支持// 其他输出选项"sourceMap": true, // 生成 source map 文件,便于调试"declaration": true, // 生成声明文件 (.d.ts)"declarationMap": true, // 为声明文件生成 source map// 更严格的类型检查选项"noUncheckedIndexedAccess": true, // 对索引签名访问启用严格检查"exactOptionalPropertyTypes": true, // 精确处理可选属性类型// 代码风格选项// "noImplicitReturns": true,           // 要求函数所有路径都有返回值// "noImplicitOverride": true,          // 要求明确标记 override 方法"noUnusedLocals": true, // 禁止声明未使用的局部变量"noUnusedParameters": true, // 禁止声明未使用的函数参数// "noFallthroughCasesInSwitch": true,  // 禁止 switch 语句中的 fallthrough// "noPropertyAccessFromIndexSignature": true, // 禁止通过属性访问语法访问索引签名// 推荐的编译选项"strict": true, // 启用所有严格类型检查选项"jsx": "react-jsx", // 使用 React JSX 转换"verbatimModuleSyntax": true, // 保持模块导入/导出语法的原样"isolatedModules": true, // 确保每个文件可以单独编译"noUncheckedSideEffectImports": true, // 禁止未检查的副作用导入"moduleDetection": "force", // 强制模块检测模式"skipLibCheck": true, // 跳过声明文件的类型检查,提高编译速度"esModuleInterop": true, // 启用 ES 模块互操作性"allowSyntheticDefaultImports": true, // 允许合成默认导入"noImplicitAny": false // 禁止隐式 any 类型(设置为 false 以允许隐式 any)},"include": ["**/*.ts"],"exclude": ["node_modules", "dist"],"ts-node": {"esm": true,"experimentalSpecifierResolution": "node"}
}

修改自动生成的文件
app.js => app.ts

import Koa from "koa";
import views from "koa-views";
import json from "koa-json";
import onerror from "koa-onerror";
import bodyparser from "koa-bodyparser";
import logger from "koa-logger";
import type { Context, Next } from "koa";
import serve from "koa-static";
import { resolve } from "path";
const app = new Koa();
// error handler
onerror(app);
// middlewares
app.use(bodyparser({enableTypes: ["json", "form", "text"],})
);
app.use(json({}));
app.use(logger());
app.use(serve(resolve("./public")));
app.use(views(resolve("./src/views"), {extension: "ejs",})
);
// logger
app.use(async (ctx: Context, next: Next) => {const start = Date.now();await next();const ms = Date.now() - start;console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
// routes
import index from "./src/routes/index.ts";
import users from "./src/routes/users.ts";
app.use(index.routes());
app.use(users.routes());
// 后续使用自动化
// import { registerRoutes } from "./src/utils/register.js";
// await registerRoutes(app, resolve("./src/routes"));export default app;

启动文件
www => www.ts

#!/usr/bin/env node
import app from "../app.ts";
import http from "http";
import debug from "debug";var port = normalizePort(process.env.PORT || '3000');
var server = http.createServer(app.callback());server.listen(port,()=>{console.log(`🚀 服务器已启动: http://localhost:${port}`);console.log(`🕒 ${new Date().toLocaleString()}`);
});
server.on('error', onError);
server.on('listening', onListening);function normalizePort(val) {var port = parseInt(val, 10);if (isNaN(port)) {// named pipereturn val;}if (port >= 0) {// port numberreturn port;}return false;
}function onError(error) {if (error.syscall !== 'listen') {throw error;}var bind = typeof port === 'string'? 'Pipe ' + port: 'Port ' + port;// handle specific listen errors with friendly messagesswitch (error.code) {case 'EACCES':console.error(bind + ' requires elevated privileges');process.exit(1);break;case 'EADDRINUSE':console.error(bind + ' is already in use');process.exit(1);break;default:throw error;}
}function onListening() {var addr = server.address();var bind = typeof addr === 'string'? 'pipe ' + addr: 'port ' + addr?.port;debug('Listening on ' + bind);
}

配置文件package.json

{"name": "koa2-typeorm-learn","version": "0.1.0","private": true,"type": "module","scripts": {"build": "tsc","start": "node dist/bin/www","dev": "nodemon --watch './**/*' -e ts,tsx --exec ts-node ./bin/www.ts","prd": "pm2 start dist/bin/www","test": "echo \"Error: no test specified\" && exit 1","debug": "nodemon --inspect --watch './**/*' -e ts,tsx --exec ts-node ./bin/www.ts"},"dependencies": {"debug": "^4.1.1","ejs": "~2.3.3","koa": "^2.7.0","koa-bodyparser": "^4.2.1","koa-convert": "^1.2.0","koa-json": "^2.0.2","koa-logger": "^3.2.0","koa-onerror": "^4.1.0","koa-router": "^7.4.0","koa-static": "^5.0.0","koa-views": "^6.2.0"},"devDependencies": {"@types/debug": "^4.1.12","@types/koa": "^3.0.0","@types/koa-bodyparser": "^4.3.12","@types/koa-json": "^2.0.23","@types/koa-logger": "^3.1.5","@types/koa-router": "^7.4.8","@types/koa-static": "^4.0.4","@types/koa-views": "^7.0.0","@types/node": "^24.2.1","nodemon": "^1.19.1","ts-node": "^10.9.2","typescript": "^5.9.2"}
}

其他文件举例示范
index.js => index.ts

import Router from "koa-router";
import type { Context, Next } from "koa";
const router = new Router();
router.get("/", async (ctx: Context, _next: Next) => {await ctx.render("index", {title: "Hello Koa 2!",});
});
router.get("/string", async (ctx: Context, _next: Next) => {ctx.body = "koa2 string";
});
router.get("/json", async (ctx: Context, _next: Next) => {ctx.body = {title: "koa2 json",};
});
export default router;

3 引入typeorm

中文文档

导入依赖

pnpm install typeorm reflect-metadata mysql2 -S

修改tsconfig.json
增加对于装饰器的支持

"emitDecoratorMetadata": true, // 允许装饰器元数据的生成
"experimentalDecorators": true // 启用实验性的装饰器支持

package.json增加scripts

"typeorm": "typeorm-ts-node-commonjs"

不推荐使用typeorm init生成配置,因为会重写一些文件

  • gitigonor
  • package.json
  • tsconfig.json

全局安装typeorm-model-generator
以便根据数据库直接生成实体

npm i typeorm-model-generator -g

执行命令基于数据库生成实体
(不推荐使用配置文件的命令,因为我这是用它报错,并且一直解决不了)

typeorm-model-generator -h hostname -d database -p port -u username -x password -e engine -o outputDirectory

-h / --host: 数据库服务器的IP地址或域名。
-d / --database: 要连接的数据库名称。
-p / --port: 数据库服务器的端口号。
-u / --user: 登录数据库的用户名。
-x / --password: 数据库密码。
-e / --engine: 数据库引擎类型(如 mysql,)。
-o / --output-dir: 生成文件的目标目录。

给tsconfig.json增加属性,避免生成的实体报错

"strictPropertyInitialization": false, // 禁止未初始化的类属性(设置为 false 以允许未初始化)

创建数据源

import "reflect-metadata";
import { DataSource } from "typeorm";
import { TRole } from "../entity/TRole.ts";
export const AppDataSource = new DataSource({type: "mysql",host: "host",port: 3306,username: "db_admin",password: "password",database: "database",synchronize: true,logging: false,entities: [TRole],migrations: [],subscribers: [],
});

创建连通性测试方法

import { AppDataSource } from "../utils/dataSource.ts";
import { TRole } from "../entity/TRole.ts";
export const testConnectivity = async () => {await AppDataSource.initialize();const roles = await AppDataSource.manager.find(TRole);console.log("All roles from the db: ", roles);
};

在app.ts中导入并执行savedPhotos

http://www.dtcms.com/a/331398.html

相关文章:

  • 14 ABP Framework 文档管理
  • java开发,匹配指定内容设置不同字体颜色
  • 嵌入式C/C++面试大全
  • 传统自然语言处理任务入口
  • css预编译器实现星空背景图
  • XJar 加密 jar 包
  • Vscode的wsl环境开发ESP32S3的一些问题总结
  • 《贵州棒球百科》体育赛事排名·棒球1号位
  • 建造者模式C++
  • 串口通信中,实现串口接收函数时,避免数据丢失或被覆盖的方法
  • 20250814在荣品RD-RK3588开发板的Android13下解决卡迪的LCD屏在开机的时候brightness最暗【背光的pwm信号的极性反了】
  • 机器学习核心概念与实践笔记
  • 安卓设备通过USB,连接继电器,再通过继电器开关闸机
  • 前端包管理工具
  • 【FreeRTOS】任务管理:创建与删除任务,任务优先级与阻塞
  • 计算机网络---传输控制协议Transmission Control Protocol(TCP)
  • Redis的 ​​散列(Hash)​​ 和 ​​列表(List)​​ 数据结构操作详解
  • 力扣-64.最小路径和
  • 【AI推理部署教程】使用 vLLM 运行智谱 GLM-4.5V 视觉语言模型推理服务
  • 电商双 11 美妆数据分析总结(补充)
  • 入门概述(面试常问)
  • 中久数创——笔试题
  • Android构建工具版本兼容性对照表
  • Git 中切换到指定 tag
  • 会议系统核心流程详解:创建、加入与消息交互
  • 卫星通信链路预算之七:上行载噪比计算
  • MySQL-dble分库分表方案
  • 【最新版】怎么下载mysqlclient并成功安装?
  • 物化视图优先迁移大表,缩短逻辑迁移时间
  • MySql——binlog和redolog的区别