TypeScript Standards
Estándares y convenciones para desarrollo TypeScript
Regla Fundamental
Warning
TypeScript es OBLIGATORIO. Nunca usar JavaScript puro en proyectos nuevos.
Versión y Setup
- Node.js: 18+
- TypeScript: 5.0+
- Módulos: ES Modules (
"type": "module")
# Inicializar proyecto
npm init -y
npm install typescript @types/node -D
npx tsc --initConfiguración TypeScript
tsconfig.json (Strict Mode)
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}package.json
{
"name": "mi-proyecto",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext .ts,.tsx",
"format": "prettier --write src"
}
}Frameworks
Next.js 14 (Full-stack)
npx create-next-app@latest mi-proyecto --typescript --tailwind --eslint --appEstructura:
app/
├── layout.tsx
├── page.tsx
├── api/
│ └── route.ts
└── components/
Vite + React (SPA)
npm create vite@latest mi-proyecto -- --template react-tsExpress (API Node)
npm install express
npm install @types/express -Dimport express, { Request, Response } from 'express';
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/healthz', (req: Request, res: Response) => {
res.json({ ok: true });
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});Linting: ESLint
npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -D.eslintrc.cjs
module.exports = {
root: true,
env: { browser: true, es2022: true, node: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json'],
},
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
},
};Formatting: Prettier
npm install prettier -D.prettierrc
{
"semi": true,
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"trailingComma": "none"
}Styling: Tailwind CSS
Note
Siempre usar Tailwind CSS. Nunca CSS-in-JS (styled-components, emotion, etc.)
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -ptailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
theme: {
extend: {
colors: {
'ep-primary': '#1a365d',
'ep-secondary': '#c53030',
'ep-accent': '#2b6cb0',
},
},
},
plugins: [],
};Testing: Vitest
npm install vitest @testing-library/react @testing-library/jest-dom -Dvitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./src/test/setup.ts'],
},
});Ejemplo de Test
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { Button } from './Button';
describe('Button', () => {
it('renders children', () => {
render(<Button>Click me</Button>);
expect(screen.getByRole('button')).toHaveTextContent('Click me');
});
});Estructura de Proyecto React
src/
├── components/
│ ├── ui/ # Componentes base (Button, Input, etc.)
│ └── features/ # Componentes de funcionalidad
├── hooks/ # Custom hooks
├── lib/ # Utilidades
├── services/ # API calls
├── types/ # TypeScript types
├── styles/ # CSS/Tailwind
├── App.tsx
└── main.tsx