Menu

Indexed access types en TypeScript: T[K], T[number] y más

Un indexed access type lee el tipo de una propiedad de otro tipo: Person["age"] es number. Aprende T["key"], claves en unión, T[keyof T], T[number] para los elementos de un array, los índices de tuplas y (typeof arr)[number] para convertir un array const en una unión.

Esta página incluye editores ejecutables: edita, ejecuta y ve el resultado al instante.

Un indexed access type busca el tipo de una propiedad en otro tipo, con la misma sintaxis de corchetes que JavaScript usa para acceder a propiedades. Person["age"] es number, y Person["address"]["city"] es string.

La ventaja es tener una única fuente de verdad. Age no es una segunda copia de number: si Person["age"] pasa a ser string, todos los tipos escritos como Person["age"] cambian con él. Los indexed access types solo existen en compilación; no generan JavaScript.

Claves en unión y T[keyof T]

El índice puede ser una unión de claves. El resultado es la unión de los tipos de esas propiedades:

Product[keyof Product] es la forma de decir a nivel de tipos «cualquier valor de propiedad de Product». Pedir una clave que no existe es un error de compilación: Product["price"] da error TS2339: Property 'price' does not exist on type 'Product'.

Las propiedades opcionales incluyen undefined

Con strictNullChecks (activado con strict), el tipo de una propiedad opcional incluye undefined, y también su indexed access type:

type Profile = { name: string; nickname?: string };

type Nick = Profile["nickname"]; // string | undefined

Para quitar el undefined, envuélvelo: NonNullable<Profile["nickname"]> es string.

El tipo de los elementos de un array con T[number]

Los arrays se indexan con números, así que indexar un tipo array con number da el tipo de sus elementos. También funciona a través de varios niveles:

Es útil cuando un tipo viene de algo que no controlas, como un cliente de API generado: ApiResponse["data"]["users"][number] nombra el tipo del usuario sin que nadie lo haya exportado.

Tuplas: indexar por posición

Un tipo tupla se puede indexar con una posición concreta, con number para la unión de todos los tipos de sus elementos, y con "length" para su longitud como tipo literal:

(typeof arr)[number]: una unión a partir de un array const

El uso más habitual en proyectos reales: guardar una lista de valores permitidos como array (para recorrerla en ejecución) y derivar de ella el tipo unión (para que el compilador lo compruebe).

Funciona gracias a dos piezas. as const convierte el array en una tupla readonly de tipos literales; sin él, ROLES es string[] y (typeof ROLES)[number] es solo string. Después, typeof convierte el valor en un tipo, y [number] junta sus elementos en una unión. Los paréntesis son opcionales (typeof ROLES[number] significa lo mismo), pero dejan claro el orden de las operaciones.

Comprobar un string contra el array

Esa tupla readonly tiene una sorpresa. Su método includes solo acepta el tipo de sus elementos, así que no le puedes pasar un string cualquiera:

index.ts(6,25): error TS2345: Argument of type 'string' is not assignable to parameter of type '"admin" | "editor" | "viewer"'.

Amplía el array a readonly string[] para la comprobación, y convierte la función en un type guard para que una comprobación correcta reduzca el tipo del valor:

Con este patrón tienes una sola lista para las dos tareas: la comprobación en ejecución usa el array y el tipo se deriva de él, así que no pueden desincronizarse.

Indexed access en genéricos: T[K]

Dentro de un genérico, T[K] con K extends keyof T es el tipo de la propiedad que haya elegido quien llama:

function pluck<T, K extends keyof T>(items: T[], key: K): T[K][] {
  return items.map((item) => item[key]);
}

const users = [
  { name: "Ada", age: 36 },
  { name: "Linus", age: 28 },
];

const names = pluck(users, "name"); // string[]
const ages = pluck(users, "age");   // number[]

La restricción K extends keyof T es lo que hace válido T[K]. Sin ella, TypeScript no puede saber que K es una clave de T e informa error TS2536: Type 'K' cannot be used to index type 'T'.

Sintaxis de un vistazo

Se escribeSignificaResultado de ejemplo
T["key"]tipo de una propiedadPerson["age"] es number
T["a" | "b"]unión de los tipos de esas propiedadesstring | number
T[keyof T]unión de los tipos de todas las propiedadesel tipo de cada valor
T["a"]["b"]propiedad anidadaPerson["address"]["city"]
Arr[number]tipo de los elementos de un arrayUser[] da User
Tup[0]elemento de una tupla en una posicióntipo del primer elemento
Tup["length"]longitud de una tupla como literal3
(typeof arr)[number]unión de los valores de un array const"admin" | "editor"
T[typeof key]indexar con el tipo de una constanteigual que T["name"]

El índice siempre es un tipo. Person[key], donde key es una variable const, falla con dos errores: error TS2538: Type 'key' cannot be used as an index type. y error TS2749: 'key' refers to a value, but is being used as a type here. Did you mean 'typeof key'?.

Preguntas frecuentes

¿Qué es un indexed access type en TypeScript?

Un tipo escrito T[K] que busca el tipo de la propiedad K en el tipo T. Con type Person = { name: string; age: number }, Person["age"] es number. Usa la misma sintaxis de corchetes que el acceso a propiedades en JavaScript, pero trabaja con tipos en tiempo de compilación.

¿Cómo obtengo el tipo de los elementos de un array en TypeScript?

Indexa el tipo del array con number: para type Users = User[], Users[number] es User. Para un valor array, combínalo con typeof: (typeof users)[number].

¿Cómo convierto un array de strings en un tipo unión?

Declara el array con as const para que TypeScript conserve los valores literales y luego indéxalo con number: const roles = ["admin", "editor"] as const; type Role = (typeof roles)[number]; da "admin" | "editor". Sin as const el tipo de los elementos es solo string.

¿Por qué no puedo usar una variable como índice en un indexed access type?

El índice tiene que ser un tipo. Person[key] con const key = "name" falla (errores TS2538 y TS2749) porque key es un valor. Escribe Person[typeof key] o usa directamente el literal: Person["name"].

¿Qué significa T[keyof T]?

Indexa T con la unión de todas sus claves, así que el resultado es la unión de todos los tipos de sus propiedades. Para { a: string; b: number } es string | number. Es la forma de decir a nivel de tipos «cualquier valor de este objeto».

Coddy programming languages illustration

Aprende a programar con Coddy

COMENZAR