🚀 Setup Node.js + TypeScript
# Installation
npm init -y
npm install -D typescript @types/node tsx
npx tsc --init
// tsconfig.json pour Node.js
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS", // ou "NodeNext" pour ESM
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"resolveJsonModule": true
}
}
// package.json scripts
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}
🌐 Express typé
npm install express
npm install -D @types/express
import express, { Request, Response, NextFunction } from "express";
const app = express();
app.use(express.json());
// Route typée avec params et body
interface UserParams { id: string; }
interface UpdateBody { name?: string; email?: string; }
app.put<UserParams, User, UpdateBody>(
"/users/:id",
async (req: Request<UserParams, User, UpdateBody>, res: Response<User>) => {
const { id } = req.params; // string — typé
const { name } = req.body; // string | undefined — typé
const user = await updateUser(id, { name });
res.json(user);
}
);
🛡️ Middleware typé
// Étendre Request pour ajouter user
// src/types/express.d.ts
declare namespace Express {
interface Request {
user?: { id: number; role: "admin" | "user" };
}
}
// Middleware d'authentification
const authMiddleware = (req: Request, res: Response, next: NextFunction): void => {
const token = req.headers.authorization?.split(" ")[1];
if (!token) { res.status(401).json({ error: "Unauthorized" }); return; }
req.user = verifyToken(token); // maintenant typé
next();
};
✅ Validation avec Zod
npm install zod
import { z } from "zod";
// Définir le schéma ET inférer le type
const UserSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().int().min(0).max(120).optional(),
role: z.enum(["admin", "user"]).default("user")
});
// Type inféré automatiquement depuis le schéma
type User = z.infer<typeof UserSchema>;
// Dans un handler Express
app.post("/users", (req, res) => {
const result = UserSchema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.flatten() });
}
const user: User = result.data; // typé et validé
});
🗄️ Prisma ORM — TypeScript natif
npm install prisma @prisma/client
npx prisma init
// prisma/schema.prisma
model User {
id Int @id @default(autoincrement())
name String
email String @unique
createdAt DateTime @default(now())
posts Post[]
}
// Prisma génère les types automatiquement
npx prisma generate
// Utilisation — types inférés
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
// user est de type Prisma.User — entièrement typé
const user = await prisma.user.findUnique({ where: { id: 1 } });
user?.name; // string | undefined — typé
🔐 Variables d'environnement typées
npm install zod
// src/config/env.ts
import { z } from "zod";
const EnvSchema = z.object({
NODE_ENV: z.enum(["development", "production", "test"]),
DATABASE_URL: z.string().url(),
JWT_SECRET: z.string().min(32),
PORT: z.coerce.number().default(3000)
});
export const env = EnvSchema.parse(process.env);
// Lance une erreur explicite si une variable est manquante ou invalide
// Utilisation — env est entièrement typé
app.listen(env.PORT);
Bonne pratique : validez toujours vos variables d'environnement au démarrage avec Zod. Vous saurez immédiatement si une config est manquante plutôt que de découvrir le problème en production.