typescript - No se puede 'indexar tipo' usando una variable de cadena
Estoy intentando invertir los campos de un objeto si existe un valor, pero estoy obteniendo un error que no puedo descifrar.
interface Control {
name1: boolean;
name2: boolean;
...
}
const values = ['name1', 'name2', ...];
const control: Control = {
name1: false,
name2: false,
...
}
for (const value of values) {
if ((value in control) {
control[value] = !control[value]; // error
}
}
Mensaje de error:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Control'.
No index signature with a parameter of type 'string' was found on type 'Control'.ts(7053)
Sin embargo, el error desaparece si paso explícitamente uno de los campos del objeto, como control['name1']. ¿Hay algo que no estoy entendiendo?
Respuesta #1
TypeScript no sabe que tu arreglo values es un arreglo de cadenas específicas, solo que es un string[]. Intenta esto:
interface Control {
name1: boolean;
name2: boolean;
}
const values = ['name1', 'name2'] as const;
const control: Control = {
name1: false,
name2: false,
}
for (const value of values) {
if (value in control) {
control[value] = !control[value]; // error
}
}
Área de juego de TypeScript
Ese as const le indica a TypeScript que especifique el tipo de values de manera más precisa como ['name1', 'name2'] en este caso, así que cuando estés iterando a través de él, value se tipará como 'name1' | 'name2' y TypeScript entenderá que esos valores se pueden usar para indexar un Control.
Respuesta #2
La variable value puede ser cualquier valor durante la ejecución de la aplicación y TypeScript no tiene conocimiento de que sea una clave válida definida dentro del objeto control. Por lo tanto, no puede simplemente inferir el tipo de valor de control[value].
La solución es, sin embargo, muy simple, todo lo que se necesita hacer es decirle a TypeScript que el arreglo values solo contiene claves válidas del tipo Control mediante el uso de la sintaxis keyof Control:
const values: (keyof Control)[] = ['name1', 'name2'];
Aquí hay un enlace al Playground.
