Últimamente estoy probando mecanografiado y, mientras me sumergía en él, me quedé atascado en un lugar donde no podía avanzar. Así que tengo una matriz de cadenas y quiero reducirla a un objeto mientras obtengo todas las sugerencias adecuadas y la finalización del código. Aunque llegué a un lugar donde TypeScript no arroja ningún error, aún así no pude lograr el comportamiento de finalización del código. Pegar el código de muestra aquí como referencia.
interface GetObjI { [key: string]: string; } function getObj(myArray: string[]): GetObjI { return myArray.reduce((prev, curr) => { prev[curr] = curr; return prev; }, {}); } const arr = ["name", "age"]; const obj = getObj(arr); console.log(obj.age); // Here I wasn't able to achieve code completion.Con una configuración estricta de TypeScript, el código que tiene debería arrojar un error.
prev[curr] = curr;lanza
El elemento tiene implícitamente un tipo 'cualquiera' porque la expresión de tipo 'cadena' no se puede usar para indexar el tipo '{}'.
No se encontró ninguna firma de índice con un parámetro de tipo 'cadena' en el tipo '{}'.(7053)
Lo cual tiene sentido: no está proporcionando ningún tipo especial para el acumulador cuando lo está pasando, por lo que asignarle una propiedad no encaja con su tipo existente (como un objeto vacío).
Use un argumento de tipo genérico para indicar el tipo del acumulador y haga que getObj también sea genérico para que los valores en myArray se puedan pasar (en lugar de usar solo string[] , que es demasiado general).
También debe escribir la matriz pasada as const para que no se amplíe a string[] antes de la llamada a la función.
function getObj<T extends readonly string[]>(myArray: T) { // Type out the type of the full object with all properties here to be DRY type Accum = Record<T[number], T[number]>; // The object doesn't have all properties inside the callback, though // so we need to use Partial to indicate that some or all can be missing return myArray.reduce<Partial<Accum>>((prev, curr: T[number]) => { prev[curr] = curr; return prev; }, {}) as Accum; // When returning, indicate that it's no longer Partial, but has all properties } const arr = ["name", "age"] as const; const obj = getObj(arr); console.log(obj.age); Pero .reduce no es la herramienta adecuada para esta situación : requiere escritura detallada de TypeScript y no es una gran idea incluso en JavaScript estándar porque el acumulador sigue siendo el mismo objeto. Solo usa un bucle.
function getObj<T extends readonly string[]>(myArray: T) { const obj: Record<string, string> = {}; for (const prop of myArray) { obj[prop] = prop; } return obj as Record<T[number], T[number]>; } O use Object.fromEntries
const getObj = <T extends readonly string[]>(myArray: T) => Object.fromEntries(myArray.map(prop => [prop, prop])) as Record<T[number], T[number]>; Desafortunadamente, todos estos enfoques requieren ayudar a TS junto con algunos tipos de afirmaciones. Usar un bucle o reduce requiere que las propiedades se escriban como opcionales dentro del bucle, pero requeridas fuera de él, y Object.fromEntries solo proporciona un tipo de Record<string, T> en respuesta, que no es lo suficientemente específico.