با Node.js (with Node.js)
در "تایپ اسکریپت با نود" کدنویسی امن تر می شود. چون تایپ ایستا خطا را زود نشان می دهد. همچنین تکمیل خودکار بهتر می شود و تغییر کدها امن تر است.
چرا TypeScript کنار Node.js؟
مزایا ساده اند؛ امنیت تایپ ها، خطایابی سریع، نگهداری آسان، و بازآرایی امن. مانند دفتر مشق مرتب که پیدا کردن اشتباه راحت تر است.
شروع پروژه Node با TypeScript
گام ها را به ترتیب انجام بده. سپس کامپایل کن و اجرا کن.
mkdir my-ts-node-app
cd my-ts-node-app
npm init -y
npm install typescript @types/node --save-dev
npx tsc --init
ساخت پوشه کد
کد را در src بگذار. خروجی در dist قرار می گیرد.
mkdir src
نمونه tsconfig.json
این تنظیم ها رایج هستند. سپس مسیرها را با پروژه هماهنگ کن.
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
نمونه سرور Express با TypeScript
این یک سرور کوچک است. یک مدل User دارد و چند مسیر ساده.
import express, { Request, Response, NextFunction } from 'express';
import { json } from 'body-parser';
interface User {
id: number;
username: string;
email: string;
}
const app = express();
const PORT = process.env.PORT || 3000;
app.use(json());
const users: User[] = [
{ id: 1, username: 'user1', email: 'user1@example.com' },
{ id: 2, username: 'user2', email: 'user2@example.com' }
];
app.get('/api/users', (req: Request, res: Response) => {
res.json(users);
});
app.get('/api/users/:id', (req: Request, res: Response) => {
const id = parseInt(req.params.id);
const user = users.find((u) => u.id === id);
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
});
app.post('/api/users', (req: Request, res: Response) => {
const { username, email } = req.body;
if (!username || !email) {
return res.status(400).json({ message: 'Username and email are required' });
}
const newUser: User = { id: users.length + 1, username, email };
users.push(newUser);
res.status(201).json(newUser);
});
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error(err.stack);
res.status(500).json({ message: 'Something went wrong!' });
});
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
میان افزارها (Middleware) تایپ شده
می توانی ادغام اعلان انجام دهی. یعنی نوع های Express را گسترش دهی.
import { Request, Response, NextFunction } from 'express';
declare global {
namespace Express {
interface Request {
user?: { id: number; role: string };
}
}
}
export const authenticate = (req: Request, res: Response, next: NextFunction) => {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ message: 'No token provided' });
}
try {
const decoded = { id: 1, role: 'admin' };
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ message: 'Invalid token' });
}
};
export const authorize = (roles: string[]) => {
return (req: Request, res: Response, next: NextFunction) => {
if (!req.user) {
return res.status(401).json({ message: 'Not authenticated' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ message: 'Not authorized' });
}
next();
};
};
import { authenticate, authorize } from './middleware/auth';
app.get('/api/admin', authenticate, authorize(['admin']), (req, res) => {
res.json({ message: `Hello admin ${req.user?.id}` });
});
TypeORM و پایگاه داده
با تزئین گر کلاس را به جدول نگاشت کن. سپس اتصال بساز.
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
@Entity('users')
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
username: string;
@Column({ unique: true })
email: string;
@Column({ select: false })
password: string;
@Column({ default: 'user' })
role: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
import 'reflect-metadata';
import { DataSource } from 'typeorm';
import { User } from '../entity/User';
export const AppDataSource = new DataSource({
type: 'postgres',
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432'),
username: process.env.DB_USERNAME || 'postgres',
password: process.env.DB_PASSWORD || 'postgres',
database: process.env.DB_NAME || 'mydb',
synchronize: process.env.NODE_ENV !== 'production',
logging: false,
entities: [User],
migrations: [],
subscribers: [],
});
import { AppDataSource } from './config/database';
AppDataSource.initialize()
.then(() => {
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
})
.catch((err) => {
console.error('DB init error', err);
process.exit(1);
});
اسکریپت ها و اجرای توسعه
اسکریپت های رایج را در package.json بگذار. سپس توسعه راحت تر می شود.
{
"scripts": {
"build": "tsc",
"start": "node dist/server.js",
"dev": "nodemon --exec ts-node src/server.ts",
"watch": "tsc -w",
"test": "jest --config jest.config.js"
}
}
npm run dev
npm run build
npm start
دیباگ با Source Map
نقشه ها فعال اند؟ سپس اجرای زیر خطاها را به فایل های TS وصل می کند.
node --enable-source-maps dist/server.js
هشدار: از ts-node و nodemon فقط در توسعه استفاده کن. برای تولید، ابتدا کامپایل کن و بعد Node را روی خروجی اجرا کن.
جمع بندی سریع
- تایپ ها زودتر خطا را نشان می دهند.
- کد تمیزتر و ایمن تر می شود.
- پروژه را با
srcوdistمرتب نگه دار. - برای تولید، فقط فایل های JS را اجرا کن.
برای ادامه، راهنمای پیکربندی را ببین. همچنین فصل به روزرسانی های نسخه 5 را بررسی کن. و برای تکمیل، از لینک داخلی با کلیدواژه تایپ اسکریپت با نود استفاده کن.