El desarrollo de grandes aplicaciones en TypeScript requiere una estructura de proyecto bien definida para mantener la escalabilidad, mantenibilidad y eficiencia del código. Una mala organización puede llevar a problemas de acoplamiento, dificultades en la depuración y una curva de aprendizaje elevada para nuevos desarrolladores en el equipo.
En este artículo, exploraremos cómo organizar un proyecto grande en TypeScript utilizando buenas prácticas, patrones de diseño y herramientas avanzadas.
1. Configuración Inicial del Proyecto Link to heading
Antes de estructurar el código, debemos preparar un entorno robusto en TypeScript.
1.1 Crear un Proyecto TypeScript Link to heading
Ejecuta el siguiente comando para inicializar un nuevo proyecto:
mkdir my-large-ts-project && cd my-large-ts-project
npm init -y
npm install typescript --save-dev
1.2 Configuración de tsconfig.json
Link to heading
Generamos un archivo de configuración:
npx tsc --init
Modificamos el archivo tsconfig.json
con las siguientes opciones recomendadas:
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
2. Estructura de Carpetas para Grandes Proyectos Link to heading
Una estructura bien definida facilita la escalabilidad del proyecto. Un modelo recomendado es:
/my-large-ts-project
│── /src
│ ├── /config
│ │ ├── appConfig.ts
│ │ ├── dbConfig.ts
│ ├── /models
│ │ ├── userModel.ts
│ │ ├── orderModel.ts
│ ├── /services
│ │ ├── userService.ts
│ │ ├── orderService.ts
│ ├── /controllers
│ │ ├── userController.ts
│ │ ├── orderController.ts
│ ├── /routes
│ │ ├── userRoutes.ts
│ │ ├── orderRoutes.ts
│ ├── /middlewares
│ │ ├── authMiddleware.ts
│ ├── /utils
│ │ ├── logger.ts
│ ├── /tests
│ │ ├── userService.test.ts
│ ├── app.ts
│── /dist
│── package.json
│── tsconfig.json
│── README.md
Descripción de las Carpetas Link to heading
/config
: Configuración de base de datos, variables de entorno y opciones globales./models
: Definiciones de modelos y entidades./services
: Lógica de negocio (capa intermedia entre controladores y base de datos)./controllers
: Manejo de solicitudes HTTP./routes
: Definición de rutas para cada entidad./middlewares
: Middleware para autenticación, validaciones, etc./utils
: Funciones auxiliares reutilizables./tests
: Pruebas unitarias y de integración.
3. Modularización y Separación de Responsabilidades Link to heading
Dividir el código en módulos independientes mejora la reutilización y el mantenimiento.
Ejemplo: Modelo de Usuario (models/userModel.ts
)
Link to heading
export interface User {
id: string;
name: string;
email: string;
}
Ejemplo: Servicio de Usuario (services/userService.ts
)
Link to heading
import { User } from "../models/userModel";
const users: User[] = [];
export class UserService {
static getAllUsers(): User[] {
return users;
}
static addUser(user: User): void {
users.push(user);
}
}
Ejemplo: Controlador de Usuario (controllers/userController.ts
)
Link to heading
import { Request, Response } from "express";
import { UserService } from "../services/userService";
export const getUsers = (req: Request, res: Response) => {
res.json(UserService.getAllUsers());
};
export const addUser = (req: Request, res: Response) => {
const user = req.body;
UserService.addUser(user);
res.status(201).json(user);
};
4. Uso de TypeScript con Express.js Link to heading
4.1 Instalar Express y Tipos Link to heading
npm install express
npm install @types/express --save-dev
4.2 Definir las Rutas (routes/userRoutes.ts
)
Link to heading
import { Router } from "express";
import { getUsers, addUser } from "../controllers/userController";
const router = Router();
router.get("/users", getUsers);
router.post("/users", addUser);
export default router;
4.3 Configurar el Servidor (app.ts
)
Link to heading
import express from "express";
import userRoutes from "./routes/userRoutes";
const app = express();
app.use(express.json());
app.use("/api", userRoutes);
app.listen(3000, () => console.log("Servidor corriendo en http://localhost:3000"));
5. Implementación de Pruebas con Jest Link to heading
Las pruebas garantizan la estabilidad del código en proyectos grandes.
5.1 Instalar Jest Link to heading
npm install --save-dev jest ts-jest @types/jest
5.2 Configurar Jest en package.json
Link to heading
"scripts": {
"test": "jest --config jest.config.js"
}
5.3 Ejemplo de Prueba (tests/userService.test.ts
)
Link to heading
import { UserService } from "../services/userService";
test("Agregar un usuario", () => {
UserService.addUser({ id: "1", name: "Juan", email: "juan@example.com" });
expect(UserService.getAllUsers().length).toBe(1);
});
Conclusión Link to heading
Estructurar grandes proyectos en TypeScript requiere una organización clara y modular. Al seguir estas prácticas, logramos:
✅ Código mantenible y escalable. ✅ Separación clara de responsabilidades. ✅ Reutilización y modularidad del código. ✅ Facilidad para pruebas unitarias e integración.