Estoy tratando de escribir la siguiente función de utilidad que toma una matriz y devuelve un objeto como se muestra a continuación
const convertListToMap = (list, key, secondKey) => { const map = {}; for (const ele of list) { map[ele[key]] = ele[secondKey] } return map; } console.log(convertListToMap([{name: 'isaac', age: 17}, {name: 'john', age: 20}], 'name', 'age')); console.log(convertListToMap([{race: 'chinese', language: 'mandarin'}, {race: 'malay', language: 'melayu'}], 'race', 'language')); Como puede ver, key y secondKey son algo dinámicos, dependiendo de la list de parámetros, así que supongo que los generics son el camino a seguir. A continuación se muestra mi intento
const convertListToMap = < T extends object, U extends keyof T, V extends keyof T >( list: T[], key: U, secondKey: V ) => { const map = {} as Record<U, V>; for (const ele of list) { map[ele[key]] = ele[secondKey]; } return map; }; Sin embargo, lo anterior me da el error Type 'T[U]' cannot be used to index type 'Record<U, V>' , preguntándome qué parte hice mal.
ACTUALIZACIONES
Mi último intento es actualizar la firma del map como se muestra a continuación.
const map = {} as Record<T[U], T[V]>; for (const ele of list) { map[ele[key]] = ele[secondKey]; } return map; Con este último intento, la asignación de valor a la variable de map está bien, pero recibo un error en la línea de declaración de registro con el siguiente error
El tipo 'T[U]' no satisface la restricción 'cadena | número | símbolo'. El tipo 'T[keyof T]' no se puede asignar al tipo 'cadena | número | símbolo'. Escriba 'T[cadena] | T[número] | T[símbolo]' no se puede asignar al tipo 'cadena | número | símbolo'. El tipo 'T[cadena]' no se puede asignar al tipo 'cadena | número | símbolo'. El tipo 'T[cadena]' no se puede asignar al tipo 'símbolo'. El tipo 'T[keyof T]' no se puede asignar al tipo 'símbolo'. El tipo 'T[U]' no se puede asignar al tipo 'símbolo'. El tipo 'T[keyof T]' no se puede asignar al tipo 'símbolo'. Escriba 'T[cadena] | T[número] | T[símbolo]' no se puede asignar al tipo 'símbolo'. El tipo 'T[cadena]' no se puede asignar al tipo 'símbolo'.ts(2344)
El problema con el último intento fue que Record parecía esperar solo string | number | symbol , y dado que TypeScript no está seguro de qué será T[U] , por lo tanto, arrojó el error. Descubrí que podemos contarle a TS un poco más sobre T como se muestra a continuación
const convertListToMap = < T extends { [key: string|number]: string | number }, U extends keyof T, V extends keyof T >( list: T[], key: U, secondKey: V ) => { const map = {} as Record<T[U], T[V]>; for (const ele of list) { map[ele[key]] = ele[secondKey]; } return map; }; De lo anterior, le estamos diciendo a mecanografiado que T será un objeto con key de string , y el valor será de tipo string | number , con eso, TypeScript está contento con la definición Record<T[U], T[V]>
Esta solución funciona muy bien y TS puede inferir correctamente
const personObj = convertListToMap([{name: 'isaac', age: 17}, {name: 'john', age: 20}], 'name', 'age') // const personObj: Record<string, number> const languageObj = convertListToMap([{race: 'chinese', language: 'mandarin'}, {race: 'malay', language: 'melayu'}], 'race', 'language') // const languageObj: Record<string,string>