TypeScript
Arrays, readonly arrays y tuples
Tipado de arrays, readonly arrays y tuples en TypeScript, incluyendo mutabilidad, longitud fija, posiciones conocidas, inferencia y unions relacionadas.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
TypeScript
Tipado de arrays, readonly arrays y tuples en TypeScript, incluyendo mutabilidad, longitud fija, posiciones conocidas, inferencia y unions relacionadas.
Un array describe una secuencia de longitud variable cuyos elementos comparten un contrato. Una tuple describe posiciones conocidas con tipos específicos.
const prices: number[] = [10, 20, 30];
const coordinate: [number, number] = [4, 8];const names: string[] = [];
const prices: Array<number> = [];Son equivalentes en intención.
T[] suele ser más compacta. Array<T> puede leerse mejor dentro de tipos genéricos complejos.
const values = [1, 2, 3];TypeScript infiere number[].
const values = [1, "two"];Puede inferir (string | number)[] porque busca un tipo común para todos los elementos.
const mixed: (string | number)[] = [
"one",
2,
];Cada posición puede ser string o number.
let homogeneous: string[] | number[];La variable contiene un array completo de strings o uno completo de números.
Los paréntesis cambian el contrato.
const products: Product[] = [];
products.push(product);
products.pop();
products.sort(compareProducts);const impide reasignar el binding, pero el array continúa mutable.
function calculateTotal(
products: readonly Product[],
) {
return products.reduce(
(total, product) => total + product.price,
0,
);
}Dentro de la función no puedes:
products.push(product);
products.sort(compareProducts);El contrato comunica que la función solo observa la colección.
const products: ReadonlyArray<Product> = [];Es equivalente a readonly Product[].
const mutable: Product[] = [];
const readable: readonly Product[] = mutable;Un consumidor readonly puede observar un array mutable.
La dirección contraria no es segura:
const mutableAgain: Product[] = readable;Si fuera permitida, podría mutar una colección prometida como readonly.
type Product = {
name: string;
};
const products: readonly Product[] = [
{ name: "Keyboard" },
];
products[0].name = "Mouse";El array no puede cambiar su estructura mediante esa referencia, pero sus objetos siguen siendo mutables.
Para mayor profundidad necesitas tipos readonly anidados y, si importa en runtime, una estrategia de inmutabilidad real.
const sorted = products.toSorted(compareProducts);
const reversed = products.toReversed();
const updated = products.with(0, replacement);Retornan arrays nuevos y funcionan bien con contratos readonly en runtimes compatibles.
const names = products.map(
(product) => product.name,
);El tipo del nuevo array se infiere desde el retorno de la callback.
const active = products.filter(
(product) => product.active,
);Para filtrar un union hacia un subtipo puede necesitarse un type predicate; se estudiará en narrowing.
const first = products[0];Sin noUncheckedIndexedAccess, el checker puede asumir Product.
Con el flag:
Product | undefinedEl array puede estar vacío o el índice quedar fuera del rango.
const last = products.at(-1);El tipo incluye undefined porque la posición puede no existir.
const coordinate: [number, number] = [4, 8];Las posiciones tienen significado:
0 → x
1 → ycoordinate[0].toFixed();
coordinate[1].toFixed();type Coordinate = [
x: number,
y: number,
];Las labels mejoran documentación y editor, pero no existen en runtime ni cambian la compatibilidad estructural.
type Range = [
start: number,
end?: number,
];La longitud puede ser 1 o 2.
type Command = [
executable: string,
...arguments: string[],
];La primera posición es fija y el resto mantiene el mismo tipo.
const coordinate: [number, number] = [4, 8];
coordinate[0] = 10;Una tuple no es readonly por defecto.
const coordinate: readonly [number, number] = [4, 8];const coordinate = [4, 8];Suele inferirse como number[], porque el array puede cambiar de longitud.
Para tuple:
const coordinate = [4, 8] as const;Tipo:
readonly [4, 8]function useStatus() {
let status = "idle";
function setStatus(value: string) {
status = value;
}
return [status, setStatus] as const;
}Sin as const puede inferirse un array de union, perdiendo qué tipo ocupa cada posición.
Para una API pública también puedes anotar:
function createPair(): readonly [
string,
(value: string) => void,
] {
// ...
}const coordinate = JSON.parse(text) as [number, number];No comprueba longitud ni tipos. Los datos externos necesitan parsing.
Tuple:
type Entry = [key: string, value: number];Objeto:
type Entry = {
key: string;
value: number;
};Usa tuple cuando:
Usa objeto cuando:
type Page<T> = {
items: readonly T[];
nextCursor: string | null;
};
function getVisibleProducts(
page: Page<Product>,
): readonly Product[] {
return page.items.filter(
(product) => product.visible,
);
}El contrato evita que el consumidor modifique accidentalmente la página recibida.
T[] y Array<T> describen el mismo concepto.readonly T[] evita mutación mediante esa referencia.noUncheckedIndexedAccess modela índices ausentes.as const puede inferir una readonly tuple.¿Cuál es la diferencia entre (string | number)[] y string[] | number[]?
El primero permite mezclar strings y números dentro del mismo array. El segundo exige que el array completo sea de strings o que el array completo sea de números.
Objetos y tipado estructural explica cómo TypeScript compara formas, propiedades requeridas y contratos abiertos.