sumar - typescript fundamentos
Error de TypeScript TS7015 al acceder a una enumeración utilizando un parámetro de tipo de cadena (4)
Soy nuevo en TypeScript y no comprendo qué debo hacer para corregir la línea que genera el error TS7015 (hacer referencia a un miembro de enumeración usando una variable de cadena) porque la línea que sigue inmediatamente no aparece (no hace referencia a un miembro de enum usando un literal de cadena):
enum State {
Happy = 0,
Sad = 1,
Drunk = 2
}
function Emote(enumKey:string) {
console.log(State[enumKey]); // error TS7015: Element implicitly has an ''any'' type because index expression is not of type ''number''.
console.log(State["Happy"]); // no error
}
"noImplicitAny": true
se establece en tsconfig.json
del proyecto, se tsconfig.json
el error
"noImplictAny": false
se establece en el tsconfig.json
del proyecto, no se detecta ningún error
Estoy compilando con "ntypescript": "^1.201603060104.1"
Ahora estoy compilando con "tsc": "1.8.10"
C:>npm install -g typescript
`-- [email protected]
Verificando instalación:
C:/>tsc --version
Version 1.8.10
Aquí está mi archivo tsconfig.json
:
{
"compileOnSave": true,
"compilerOptions": {
"target": "ES5",
"module": "System",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": true,
"noImplicitAny": true,
"sourceMap": true,
"mapRoot": "map/",
"diagnostics": true
},
"exclude": [
"node_modules",
"typings"
]
}
Aquí está la salida del compilador:
C:/>tsc
test.ts(8,17): error TS7015: Element implicitly has an ''any'' type because index expression is not of type ''number''.
Puede evitar este error con la opción del compilador sin perder todas las verificaciones nulas estrictas
"suppressImplicitAnyIndexErrors": true
Si está utilizando TypeScript 2.1+, puede cambiar el tipo de keyof typeof State
a keyof typeof State
, como esto:
function Emote(enumKey: keyof typeof State) {...}
o, si se requiere que la entrada de la función sea una string
, esto:
var state : State = State[enumKey as keyof typeof State];
Explicación:
El error se genera porque TypeScript, al ser una cadena arbitraria, no sabe si enumKey
es el nombre de un miembro de State
. TypeScript 2.1+ introdujo el operador keyof
que devuelve una unión de los nombres de propiedad pública conocidos de un tipo. El uso de keyof
nos permite afirmar que la propiedad está de hecho en el objeto de destino.
Sin embargo, cuando creas una enumeración, TypeScript produce tanto un tipo (que siempre es un subtipo de number
) como un valor (el objeto enum al que puedes hacer referencia en expresiones). Cuando escriba la keyof State
, en realidad obtendrá una unión de los nombres de propiedad literales de number
. Para obtener los nombres de propiedad del objeto enum, puede usar keyof typeof State
.
Fuentes:
https://github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types
Sospecho que tiene que ver con el nuevo soporte de TS 1.8.x para literales de cadenas en estas situaciones. Sucede que TS sabe que "Happy" es un índice de cadena válido, pero no sabe si enumKey
será o no. Puedes arreglarlo lanzándolo a un <any>
, así:
function Emote(enumKey:string) {
console.log(State[enumKey]); // error TS7015: Element implicitly has an ''any'' type because index expression is not of type ''number''.
console.log(State["Melancholy"]); // error TS7015: Element implicitly has an ''any'' type because index expression is not of type ''number''.
console.log(State["Happy"]); // no error
console.log(State[<any>enumKey]); // no error
console.log(State[<any>"Melancholy"]); // no error
}
(Por cierto, creo que esto es nuevo: no pude reproducir este error con 1.8.9, pero tan pronto como actualicé a 1.8.10, pude).
También es interesante que hubiera esperado que esto funcionara sin el error, pero no lo hace:
function TypedEmote(enumKey:''Happy''|''Sad''|''Drunk''){
console.log(State[enumKey]);
}
Debe ser algo sobre la especificación de TS que no entiendo, o tal vez simplemente no hayan logrado solucionar ese problema todavía.
var stateName = "Happy"
var state = <State>parseInt(State[<any>stateName]);
Esto es lo que tuve que hacer para hacer feliz al compilador.