Patrones
¿Cómo conservo la relación entre cada clave y su valor al iterar `Object.entries`?
Construye una unión de tuplas clave/valor con un tipo mapeado y encierra la aserción inevitable en un ayudante.
La receta
type Entry<T extends object> = { [K in keyof T]-?: readonly [K, T[K]] }[keyof T] function typedEntries<T extends object>(value: T): Entry<T>[] { return Object.keys(value).map(key => [key, value[key as keyof T]] as unknown as Entry<T> ) } const settings = { dark: true, retries: 3 } const entries = typedEntries(settings)
La compilación compila esto y comprueba cada resultado de abajo.
Cómo funciona
- 01
readonly [K, T[K]]Cada propiedad mapeada se convierte en una tupla cuyo valor está ligado a esa clave exacta.
- 02
}[keyof T]Indexar colapsa la tabla en una unión discriminada de entradas.
Lo que obtienes
readonly ['a', 1] extends Entry<{ a: 1; b: 'x' }> ? true : false
→truereadonly ['b', 'x'] extends Entry<{ a: 1; b: 'x' }> ? true : false
→truereadonly ['a', 'wrong'] extends Entry<{ a: 1; b: 'x' }> ? true : false
→false
Dónde falla
Como con claves tipadas, la aserción supone que no hay propiedades extra más allá de `keyof T`. Úsala con objetos propios, no con valores sin validar de API o JSON.
Conclusión
Un objeto mapeado indexado por `keyof` crea con precisión una unión correlacionada de tuplas.
