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 --init

Configuració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 --app

Estructura:

app/
├── layout.tsx
├── page.tsx
├── api/
│   └── route.ts
└── components/

Vite + React (SPA)

npm create vite@latest mi-proyecto -- --template react-ts

Express (API Node)

npm install express
npm install @types/express -D
import 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 -p

tailwind.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 -D

vitest.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