🚀 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.
📝 Exercices T08 🎯 QCM T08 ▶ Mini-projet 🏆 Projet Final →