1. Configurar el proyecto con Vite + React 18 + TypeScript1. Set Up the Project with Vite + React 18 + TypeScript
Vite es actualmente la herramienta más rápida para crear proyectos React. El ecosistema ha migrado casi por completo de Create React App hacia Vite por su velocidad de HMR y tiempo de arranque casi instantáneo. Vite is currently the fastest tool for building React projects. The ecosystem has nearly fully migrated from Create React App to Vite for its HMR speed and near-instant startup time.
npm create vite@latest mi-app -- --template react-ts
cd mi-app
npm install
npm run dev
Esto genera un proyecto con React 18, TypeScript y el plugin oficial @vitejs/plugin-react que usa
Babel por defecto. Si prefieres el compilador SWC (mucho más rápido en proyectos grandes), usa --template react-swc-ts. Babel by default. If you prefer the SWC compiler (much faster in large projects), use --template react-swc-ts.
2. Tipado estricto desde el principio2. Strict Typing from the Start
El tsconfig.json generado por Vite incluye "strict": true, que activa reglas que previenen errores comunes en tiempo de compilación. Las más importantes: The tsconfig.json generated by Vite includes "strict": true, activating rules that prevent common compile-time errors. The most important:
strictNullChecks: obliga a manejarnullyundefinedexplícitamente.strictNullChecks: forces explicit handling ofnullandundefined.noImplicitAny: prohíbe el tipoanyimplícito.noImplicitAny: forbids implicitanytypes.strictFunctionTypes: valida correctamente los tipos de funciones en callbacks.strictFunctionTypes: correctly validates function types in callbacks.
Para componentes React con TypeScript, el patrón estándar es definir una interfaz para las props: For React components with TypeScript, the standard pattern is to define an interface for the props:
interface ButtonProps {
label: string;
onClick: () => void;
variant?: 'primary' | 'ghost';
}
export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
return (
<button className={`btn btn--${variant}`} onClick={onClick}>
{label}
</button>
);
} 3. El hook useTransition — renders no urgentes3. The useTransition Hook — Non-Urgent Renders
useTransition es el hook más importante de React 18. Permite marcar actualizaciones de estado como no urgentes, para que React las interrumpa si llega una actualización más prioritaria. useTransition is React 18's most important hook. It lets you mark state updates as non-urgent, so React can interrupt them when a higher-priority update arrives.
import { useState, useTransition } from 'react';
function SearchList() {
const [query, setQuery] = useState('');
const [results, setResults] = useState<string[]>([]);
const [isPending, startTransition] = useTransition();
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
setQuery(e.target.value); // urgente: actualiza el input de inmediato
startTransition(() => {
// no urgente: filtra 10 000 items sin bloquear la UI
setResults(heavyFilter(e.target.value));
});
}
return (
<>
<input value={query} onChange={handleChange} placeholder="Buscar..." />
{isPending ? <span>Cargando...</span> : <ul>{results.map(r => <li key={r}>{r}</li>)}</ul>}
</>
);
} 4. useDeferredValue — valor diferido para renders pesados4. useDeferredValue — Deferred Value for Heavy Renders
useDeferredValue es similar a useTransition pero actúa sobre un valor. Ideal cuando no controlas el estado que dispara el render costoso. useDeferredValue is similar to useTransition but acts on a value. Ideal when you don't directly control the state triggering the expensive render.
import { useDeferredValue, useMemo } from 'react';
function FilteredTable({ data, filter }: { data: Row[]; filter: string }) {
const deferredFilter = useDeferredValue(filter);
const filteredRows = useMemo(
() => data.filter(row => row.name.includes(deferredFilter)),
[data, deferredFilter]
);
return <Table rows={filteredRows} />;
} 5. Suspense con datos asincrónicos5. Suspense with Asynchronous Data
React 18 hace que Suspense sea compatible con la carga de datos. Junto con TanStack Query o el nuevo use() hook, puedes declarar la carga asincrónica de forma elegante: React 18 makes Suspense compatible with data loading (not just lazy imports). Together with TanStack Query or the new use() hook, you can handle async loading elegantly:
import { Suspense } from 'react';
async function UserProfile({ userId }: { userId: string }) {
const user = await fetchUser(userId); // en React Server Components
return <div>{user.name}</div>;
}
export function Page() {
return (
<Suspense fallback={<Skeleton />}>
<UserProfile userId="123" />
</Suspense>
);
} 6. Mejores prácticas con TypeScript + React 186. Best Practices with TypeScript + React 18
- Usa
React.FCcon moderación — preferir funciones normales con tipos explícitos.UseReact.FCsparingly — prefer plain functions with explicit types. - Tipea los eventos del DOM:
React.MouseEvent<HTMLButtonElement>,React.ChangeEvent<HTMLInputElement>.Type DOM events:React.MouseEvent<HTMLButtonElement>,React.ChangeEvent<HTMLInputElement>. - Prefiere
as constsobreenumpara uniones de strings.Preferas constoverenumfor string unions. - Usa
Readonly<T>yReadonlyArray<T>para prevenir mutaciones accidentales.UseReadonly<T>andReadonlyArray<T>to prevent accidental mutations. - Habilita
exactOptionalPropertyTypesen tsconfig para tipado aún más estricto.EnableexactOptionalPropertyTypesin tsconfig for even stricter typing.
ConclusiónConclusion
React 18 con TypeScript es la combinación ideal para construir aplicaciones web modernas y mantenibles. El Concurrent Renderer abre un nivel completamente nuevo de control sobre la UX que antes era imposible sin soluciones externas complicadas. React 18 with TypeScript is the ideal combination for building modern, maintainable web applications. The Concurrent Renderer opens a completely new level of UX control that was previously impossible without complex external tooling.
Si buscas un desarrollador con experiencia real en React 18 + TypeScript, contáctame aquí. Trabajo de forma remota para clientes en Latinoamérica, España y Estados Unidos. Looking for a developer with real-world React 18 + TypeScript experience? Contact me here. I work remotely for clients across Latin America, Spain and the United States.