Kodokon kodokon.com

Mapped types y key remapping: transformar tipos

Comprende cómo los mapped types homomórficos preservan los modificadores y cómo la cláusula as renombra o filtra claves.

8 min · 3 preguntas

Abrir esta lección en Kodokon

Un mapped type itera sobre un conjunto de claves para producir un nuevo tipo de objeto. La forma [K in keyof T] se llama homomórfica: el compilador sabe que la estructura proviene de T y copia automáticamente los modificadores readonly y ? de cada propiedad original. Los prefijos + y - permiten añadir o eliminar explícitamente estos modificadores: esta es exactamente la maquinaria interna detrás de Partial, Required y Readonly.

TYPESCRIPT
type Mutable<T> = {
  -readonly [K in keyof T]-?: T[K];
};

interface Config {
  readonly host?: string;
  readonly port?: number;
}

type Draft = Mutable<Config>;
// { host: string; port: number }
Los prefijos - eliminan readonly y la opcionalidad.

Desde TypeScript 4.1, la cláusula as habilita el key remapping: cada clave puede renombrarse sobre la marcha, normalmente mediante un tipo de literal de plantilla. Y si la cláusula produce never, la clave simplemente se elimina del resultado: este es el mecanismo oficial de filtrado de propiedades. Observa el & string en el ejemplo: keyof T puede contener claves symbol o number, que son incompatibles con un literal de plantilla.

TYPESCRIPT
type Getters<T> = {
  [K in keyof T & string as `get${Capitalize<K>}`]:
    () => T[K];
};

interface User { name: string; age: number }
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number }

type OnlyMethods<T> = {
  [K in keyof T as
    T[K] extends (...args: never[]) => unknown
      ? K : never]: T[K];
};
Renombrar con as, filtrar produciendo never.

Una sutileza de la especificación que a menudo se pasa por alto: aplicado a un array o una tupla, un mapped type homomórfico no produce un objeto con las claves 0, 1 y length. El compilador preserva la naturaleza del tipo: transforma los elementos y mantiene la forma de array o tupla. Esto es lo que permite que Readonly<[number, string]> siga siendo una tupla. Esa preservación desaparece en cuanto el mapped type deja de ser homomórfico, por ejemplo con [P in K] donde K es una unión arbitraria de claves.

TYPESCRIPT
type Immutable<T> = {
  readonly [K in keyof T]: T[K];
};

type Pair = Immutable<[number, string]>;
// readonly [number, string]: the tuple survives

type List = Immutable<string[]>;
// readonly string[]
Un mapped type homomórfico respeta arrays y tuplas.

Prueba de conocimientos

Comprueba que has retenido los puntos clave de esta lección.

  1. En un key remapping, ¿qué ocurre cuando la cláusula as produce never para una clave?
    • La propiedad recibe el tipo never
    • La clave se elimina del tipo resultante
    • El compilador emite un error
  2. ¿Qué produce { readonly [K in keyof T]: T[K] } cuando se aplica a la tupla [number, string]?
    • Un objeto con las claves 0, 1 y length
    • readonly [number, string]
    • readonly (number | string)[]
    • Un error de compilación
  3. ¿Cuál es el efecto del modificador -? en un mapped type?
    • Hace que la propiedad sea opcional
    • Elimina la opcionalidad y el undefined que introdujo
    • Elimina el modificador readonly
    • Elimina la propiedad del tipo