← Volver al blog·Tutoriales

10 tips avanzados de TypeScript que mejorarán tu código

Técnicas avanzadas de TypeScript que usamos a diario: utility types, inferencia, guards y patrones que harán tu código más seguro y mantenible.

·5 min de lectura
TypeScriptJavaScriptTipsDesarrollo
10 tips avanzados de TypeScript que mejorarán tu código

TypeScript es mucho más que añadir : string a tus variables. Estos son los tips avanzados que usamos en Fluxer Labs para escribir código más seguro y expresivo.

1. Const assertions para literales

// Sin as const
const config = {
  endpoint: '/api/users',
  method: 'GET'
};
// tipo: { endpoint: string, method: string }

// Con as const
const config = {
  endpoint: '/api/users',
  method: 'GET'
} as const;
// tipo: { readonly endpoint: '/api/users', readonly method: 'GET' }

Útil para configuraciones que no deben cambiar.

2. Discriminated unions para estados

// ❌ Mal: campos opcionales confusos
type ApiResponse = {
  data?: User;
  error?: string;
  loading?: boolean;
};

// ✅ Bien: estados claros y mutuamente excluyentes
type ApiResponse =
  | { status: 'loading' }
  | { status: 'success'; data: User }
  | { status: 'error'; error: string };

function handleResponse(response: ApiResponse) {
  switch (response.status) {
    case 'loading':
      return <Spinner />;
    case 'success':
      return <UserCard user={response.data} />; // data existe seguro
    case 'error':
      return <Error message={response.error} />; // error existe seguro
  }
}

3. Template literal types

type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type ApiVersion = 'v1' | 'v2';

// Genera todas las combinaciones automáticamente
type ApiEndpoint = `/${ApiVersion}/${string}`;
type RequestKey = `${HttpMethod}:${ApiEndpoint}`;

// 'GET:/v1/users', 'POST:/v2/products', etc.
const cache: Record<RequestKey, unknown> = {};

4. Satisfies para validar sin perder inferencia

type Colors = Record<string, [number, number, number]>;

// Con type annotation: perdemos los keys específicos
const colors: Colors = {
  red: [255, 0, 0],
  green: [0, 255, 0],
};
colors.red; // OK
colors.blue; // OK (pero no existe!) - TypeScript no sabe qué keys hay

// Con satisfies: validamos Y mantenemos inferencia
const colors = {
  red: [255, 0, 0],
  green: [0, 255, 0],
} satisfies Colors;
colors.red; // OK
colors.blue; // Error! Property 'blue' does not exist

5. Type guards personalizados

type Fish = { swim: () => void };
type Bird = { fly: () => void };

// Type guard con 'is'
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

function move(pet: Fish | Bird) {
  if (isFish(pet)) {
    pet.swim(); // TypeScript sabe que es Fish
  } else {
    pet.fly(); // TypeScript sabe que es Bird
  }
}

6. Infer en conditional types

// Extraer tipo de retorno de una función
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// Extraer tipo de elementos de un array
type ArrayElement<T> = T extends (infer E)[] ? E : never;

// Extraer props de un componente React
type PropsOf<T> = T extends React.ComponentType<infer P> ? P : never;

// Uso
type UserProps = PropsOf<typeof UserCard>; // { name: string; age: number }

7. Mapped types con modificadores

type User = {
  id: number;
  name: string;
  email: string;
};

// Hacer todas las propiedades opcionales
type PartialUser = Partial<User>;

// Hacer todas las propiedades requeridas
type RequiredUser = Required<PartialUser>;

// Hacer todas las propiedades readonly
type ReadonlyUser = Readonly<User>;

// Crear un tipo solo con algunas keys
type UserCredentials = Pick<User, 'email'>;

// Crear un tipo sin algunas keys
type PublicUser = Omit<User, 'email'>;

// Customizado: hacer solo algunas propiedades opcionales
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type UserWithOptionalEmail = PartialBy<User, 'email'>;

8. Exhaustive checks con never

type Status = 'pending' | 'approved' | 'rejected';

function handleStatus(status: Status): string {
  switch (status) {
    case 'pending':
      return 'Esperando...';
    case 'approved':
      return 'Aprobado!';
    case 'rejected':
      return 'Rechazado';
    default:
      // Si añades un nuevo status y olvidas manejarlo,
      // TypeScript dará error aquí
      const _exhaustive: never = status;
      return _exhaustive;
  }
}

9. Branded types para IDs

// Evita mezclar IDs de diferentes entidades
type UserId = string & { readonly brand: unique symbol };
type PostId = string & { readonly brand: unique symbol };

function createUserId(id: string): UserId {
  return id as UserId;
}

function createPostId(id: string): PostId {
  return id as PostId;
}

function getUser(id: UserId) { /* ... */ }
function getPost(id: PostId) { /* ... */ }

const userId = createUserId('user-123');
const postId = createPostId('post-456');

getUser(userId); // OK
getUser(postId); // Error! No puedes pasar PostId donde se espera UserId

10. Utility type personalizado: DeepPartial

type DeepPartial<T> = T extends object
  ? { [P in keyof T]?: DeepPartial<T[P]> }
  : T;

type Config = {
  server: {
    port: number;
    host: string;
    ssl: {
      enabled: boolean;
      cert: string;
    };
  };
  database: {
    url: string;
  };
};

// Todas las propiedades anidadas son opcionales
type PartialConfig = DeepPartial<Config>;

const config: PartialConfig = {
  server: {
    port: 3000,
    // host y ssl son opcionales
  },
  // database es opcional
};

Bonus: Configuración recomendada de tsconfig

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true
  }
}

Conclusión

TypeScript es una herramienta poderosa cuando aprovechas todo su potencial. Estos patrones no son solo para presumir en code reviews - realmente previenen bugs y hacen el código más mantenible.

Empieza incorporando uno o dos de estos tips en tu próximo proyecto y ve añadiendo más conforme te sientas cómodo.


¿Quieres que tu equipo domine TypeScript? En Fluxer Labs ofrecemos formación y consultoría. Contáctanos.

Suscríbete al newsletter

Recibe los últimos artículos sobre desarrollo, IA y tecnología directamente en tu email.

Respetamos tu privacidad. Puedes darte de baja en cualquier momento.