← Blog

TypeScript Quick Reference

TypeScript Quick Reference — referencia completa de básico a avanzado

Nivel Básico

¿Qué es TypeScript?

TypeScript es JavaScript con tipos.

Añade:

TypeScript se compila a JavaScript.


Tipos básicos

const name: string = "Alberto";
const age: number = 30;
const isAdmin: boolean = true;

Arrays

const names: string[] = ["Alberto", "Juan"];

Objetos

const user: {
  name: string;
  age: number;
} = {
  name: "Alberto",
  age: 30
};

Funciones

function sum(a: number, b: number): number {
  return a + b;
}

void

function log(): void {
  console.log("hello");
}

La función no devuelve nada útil.


any

let value: any = "hello";

Desactiva TypeScript.

Evitar salvo casos concretos.


unknown

let value: unknown;

Obliga a validar antes de usar.

Más seguro que any.


Union Types

let value: string | number;

Puede ser uno de varios tipos.


Optional Properties

type User = {
  name?: string;
}

La propiedad puede no existir.


Type Narrowing

function print(value: string | number) {
  if (typeof value === "string") {
    value.toUpperCase();
  }
}

TypeScript reduce el tipo tras una comprobación.


type vs interface

interface

Más usada para contratos de objetos extensibles.

interface User {
  name: string;
}

type

Más flexible para unions y composición.

type Status = "loading" | "success";

Literal Types

const status = "loading";

Tipo inferido: "loading"


as const

Preserva valores literales exactos y añade readonly.

const COLORS = {
  primary: "#000"
} as const;

Resultado:

{
  readonly primary: "#000";
}

readonly

type User = {
  readonly name: string;
}

Evita mutaciones desde TypeScript.


Tuplas

type Pair = [string, number];

Array con posiciones y longitud concretas.


enum

enum Status {
  Loading,
  Success,
  Error
}

Actualmente muchos equipos prefieren as const.


Generics

function identity<T>(value: T): T {
  return value;
}

Permiten reutilizar lógica sin perder tipos.


keyof

type User = {
  name: string;
  age: number;
}

type Keys = keyof User;

Resultado: "name" | "age"


typeof

Obtiene el tipo de una variable.

const user = {
  name: "Alberto"
};

type User = typeof user;

Resultado:

type User = {
  name: string;
}

Nivel Medio

Utility Types

Partial<T>

Convierte propiedades en opcionales.

Partial<User>

Required<T>

Convierte propiedades opcionales en obligatorias.

Required<User>

Pick<T, K>

Selecciona propiedades concretas.

Pick<User, "name">

Omit<T, K>

Elimina propiedades concretas.

Omit<User, "password">

Record<K, T>

Crea objetos tipo diccionario.

Record<string, number>

Discriminated Unions

type State =
  | { status: "loading" }
  | { status: "success"; data: string[] }
  | { status: "error"; error: string }

Permiten modelar estados válidos.

Muy usado en:


never

Representa un valor imposible.

type A = string & number;
// never

Muy usado en exhaustive checks.


Generic Constraints

function merge<T extends object>(value: T) {}

Restringe qué tipos acepta el genérico.


keyof typeof

const COLORS = {
  primary: "#000",
  secondary: "#fff"
} as const;

type Color = keyof typeof COLORS;

Resultado: "primary" | "secondary"


Awaited<T>

Desenvuelve Promises.

Awaited<Promise<string>>
// string

ReturnType<T>

Obtiene el tipo de retorno de una función.

ReturnType<typeof getUser>

Awaited<ReturnType<typeof fn>>

Muy usado en loaders y fetch async.

type LoaderData = Awaited<ReturnType<typeof userLoader>>;

Type Assertions

const user = {} as User;

NO valida runtime.

Solo modifica cómo TypeScript interpreta el valor.


Function es mala práctica

onClick: Function

Demasiado genérico. Preferible:

onClick: () => void

{} vs object

{}

Cualquier valor excepto null y undefined.

object

Cualquier valor no primitivo.


useState<User>()

const [user, setUser] = useState<User>()

Realmente es: User | undefined


React.ReactNode

Representa cualquier cosa renderizable por React.

Incluye:


JSX.Element

Representa JSX concreto.

<div>Hello</div>

Más restrictivo que ReactNode.


Nivel Avanzado

Mapped Types

Permiten transformar las propiedades de un tipo.

type User = {
  name: string;
  age: number;
};

type ReadonlyUser = {
  readonly [K in keyof User]: User[K];
};

Resultado:

type ReadonlyUser = {
  readonly name: string;
  readonly age: number;
}

Base interna de utilities como Readonly<T> o Partial<T>.


Conditional Types

Permiten decidir un tipo según una condición.

type IsString<T> = T extends string
  ? true
  : false;

Ejemplo:

type A = IsString<string>; // true
type B = IsString<number>; // false

infer

Permite extraer un tipo dentro de un conditional type.

type UnwrapPromise<T> =
  T extends Promise<infer U>
    ? U
    : T;

Ejemplo:

type Result = UnwrapPromise<Promise<string>>;
// string

Muy usado para crear utilities avanzadas.


Template Literal Types

Permiten construir tipos string a partir de otros strings.

type Size = "sm" | "md" | "lg";

type ClassName = `button-${Size}`;

Resultado:

type ClassName =
  | "button-sm"
  | "button-md"
  | "button-lg";

Muy útil para variantes, eventos o nombres derivados.


Indexed Access Types

Permiten obtener el tipo de una propiedad.

type User = {
  id: string;
  profile: {
    name: string;
    age: number;
  };
};

type Profile = User["profile"];

También podés obtener tipos de arrays:

type Users = User[];

type SingleUser = Users[number];
// User

Exhaustive Checks

Sirven para asegurarte de que cubrís todos los casos de una union.

type State =
  | { status: "loading" }
  | { status: "success"; data: string[] }
  | { status: "error"; error: string };

function handle(state: State) {
  switch (state.status) {
    case "loading":
      return "Loading";
    case "success":
      return state.data.join(", ");
    case "error":
      return state.error;
    default:
      const exhaustive: never = state;
      return exhaustive;
  }
}

Si mañana añadís { status: "idle" }, TypeScript marcará error en const exhaustive: never = state porque idle no está gestionado.


satisfies

Comprueba que un valor cumple un tipo sin perder inferencia literal.

type Route = {
  path: string;
  protected: boolean;
};

const routes = {
  home: { path: "/", protected: false },
  dashboard: { path: "/dashboard", protected: true }
} satisfies Record<string, Route>;

Con satisfies, routes.home.path sigue siendo "/" (literal). Con anotación directa const routes: Record<string, Route>, perdés esa información concreta.


NonNullable<T>

Elimina null y undefined de un tipo.

type Value = string | null | undefined;

type CleanValue = NonNullable<Value>;
// string

Extract<T, U>

Extrae de una union los tipos compatibles con otro tipo.

type Status = "loading" | "success" | "error";

type FinalStatus = Extract<Status, "success" | "error">;
// "success" | "error"

Exclude<T, U>

Elimina de una union los tipos compatibles con otro tipo.

type Status = "loading" | "success" | "error";

type NonLoadingStatus = Exclude<Status, "loading">;
// "success" | "error"

Derivar tipos desde arrays con as const

Muy usado para evitar duplicar unions.

const ROLES = ["admin", "editor", "viewer"] as const;

type Role = typeof ROLES[number];
// "admin" | "editor" | "viewer"

Composition over Inheritance

TypeScript moderno favorece composición sobre jerarquías grandes de clases.

type WithId = {
  id: string;
};

type WithTimestamps = {
  createdAt: string;
  updatedAt: string;
};

type User = WithId & WithTimestamps & {
  name: string;
};

En React encaja mejor con props, hooks y funciones que una jerarquía profunda de clases.


Runtime vs Compile Time

TypeScript valida en tiempo de compilación, no en runtime.

type User = {
  name: string;
};

const user = JSON.parse('{"name": 123}') as User;

user.name.toUpperCase(); // runtime error: name es number

Para validar datos externos necesitás validación runtime: Zod, Valibot o io-ts.


Frases útiles para entrevistas

unknown

unknown obliga a hacer narrowing antes de usar el valor.”

type vs interface

“Uso interface para contratos extensibles y type para composición avanzada y unions.”

Discriminated Unions

“Permiten modelar estados válidos e invalidar estados imposibles.”

Generics

“Los genéricos permiten reutilizar lógica sin perder inferencia de tipos.”

as const

“Preserva literal types y evita widening.”

Type Assertions

“Las type assertions no validan runtime; solo cambian cómo TypeScript interpreta el valor.”