npm init
package.json
, nơi quản lý các phụ thuộc và script của dự án.-y
giúp dùng mặc định tất cả cài đặt để bạn tiết kiệm thời gian.package.json
sẽ giúp bạn theo dõi & cài đặt các thư viện sau này.npm init
để đồng bộ quản lý các package.npm install expressnpm install --save-dev typescript supertest nodemon jest ts-jest ts-node @types/jest @types/supertest @types/express
Thư viện | Mục đích |
---|---|
express | Framework HTTP chính cho server |
typescript | Cho lập trình TypeScript chặt chẽ |
supertest | Kiểm thử API endpoints |
jest, ts-jest | Framework test và hỗ trợ TypeScript |
nodemon | Tự khởi động lại server khi đổi code |
ts-node | Chạy trực tiếp file TypeScript |
types/* | Thêm hỗ trợ type cho thư viện liên quan |
npx tsc --init
tsconfig.json
bằng:{ "exclude": ["./coverage", "./dist", "**/*.test.ts", "jest.config.js", "eslint.config.mjs"], "ts-node": { "transpileOnly": true, "files": true }, "compilerOptions": { "target": "es2016", "module": "commonjs", "rootDir": "./src", "moduleResolution": "node", "checkJs": true, "outDir": "./dist", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitAny": true, "skipLibCheck": true }}
.ts
đầu tiên.src/├── app.ts├── app.test.ts├── server.ts└── routes/ ├── user.routes.ts └── user.routes.test.ts
src/server.ts
import app from './app';
const PORT: number = 5050;
app.listen(PORT, (): void => { // eslint-disable-next-line no-console console.log(`Server is running on ${PORT}...`);});
src/app.ts
import express, { Application, Request, Response } from 'express';import { router as userRoutes } from './routes/user.routes';
const app: Application = express();
app.use('/users', userRoutes);
app.use('/', (req: Request, res: Response): void => { res.json({ message: "Miley, what's good?" });});
export default app;
src/routes/user.routes.ts
import { Router, Request, Response } from 'express';
const router = Router();
router.get('/', (req: Request, res: Response): void => { const users = ['Nicki', 'Ariana', 'Lana', 'Miley']; res.status(200).send(users);});
export { router };
npx ts-jest config:init
jest.config.js
thành:export const preset = 'ts-jest';export const testEnvironment = 'node';
src/app.test.ts
import request from 'supertest';import app from './app';
describe('Test app.ts', () => { test('Is alive route', async () => { const res = await request(app).get('/'); expect(res.body).toEqual({ message: "Miley, what's good?" }); });});
src/routes/user.routes.test.ts
import request from 'supertest';import app from '../app';
describe('User routes', () => { test('Get all users', async () => { const res = await request(app).get('/users'); expect(res.body).toEqual(['Nicki', 'Ariana', 'Lana', 'Miley']); });});
package.json
"scripts": { "test": "jest --coverage", "dev": "nodemon ./src/server.ts", "build": "tsc", "lint": "eslint src/**/*.ts", "lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix"}
"type": "module"
khỏi package.json
để tránh xung đột.npm run test
để chạy kiểm thử với báo cáo coverage chi tiết.npm run dev
khởi động server tự động restart khi có thay đổi.npm install -D eslint @eslint/js @types/eslint__js typescript-eslint eslint-plugin-prettier eslint-config-prettier
eslint.config.mjs
:import js from '@eslint/js';import tseslint from 'typescript-eslint';import eslintPluginPrettier from 'eslint-plugin-prettier';import prettier from 'eslint-config-prettier';
export default [ js.configs.recommended, ...tseslint.configs.recommended, { files: ['**/*.ts'], languageOptions: { parser: tseslint.parser, parserOptions: { project: './tsconfig.eslint.json', sourceType: 'module', }, }, plugins: { prettier: eslintPluginPrettier, }, rules: { 'no-unused-vars': 'error', 'no-undef': 'off', 'prefer-const': 'error', 'no-console': 'warn', 'no-debugger': 'warn', 'prettier/prettier': [ 'error', { singleQuote: true, semi: true, trailingComma: 'all', printWidth: 100, tabWidth: 2, }, ], }, }, prettier, { ignores: ['dist/**', 'node_modules/**', 'coverage/**'], },];
tsconfig.eslint.json
để ESLint hiểu được cấu hình TypeScript:{ "extends": "./tsconfig.json", "include": ["src/**/*.ts", "src/**/*.tsx"], "exclude": ["node_modules", "dist"]}