我正在尝试使用JavaScript使用API。
端点每次可以给我一个具有唯一键的对象,例如:
{
"-MKlw6VSTSf-FPBaTxfB": {
"created_at": 1603934385.9833121,
"jugadores": 0,
"posiciones": 4
},
"-MKlxam1Zjtz14wZgMNp": {
"created_at": 1603934776.2540152,
"jugadores": 0,
"posiciones": 4
},
"-MKm8JvbKJmMAumJbmoU": {
"created_at": 1603937848.809657,
"jugadores": 0,
"posiciones": 4
},
"-ML3-HtshKPcKrME5Jk6": {
"created_at": 1604237470.857504,
"jugadores": 0,
"posiciones": 4
}
}
或者它可以给我这样的错误:
{
"error": true,
"mensaje": "Hubo un error"
}
我已经声明了以下类型:
type APIError = {
error: boolean
mensaje: string
}
type ListadoJuegosPublicos = {
[key:string]: {
jugadores: number
posiciones: number
created_at: number
}
}
我有这个函数签名来检索数据:
async juegosPublicos ():Promise<APIError|ListadoJuegosPublicos>
该功能按预期工作。但是,当我尝试遍历响应时,出现此错误:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'APIError | ListadoJuegosPublicos'.
No index signature with a parameter of type 'string' was found on type 'APIError | ListadoJuegosPublicos'.ts(7053)
这是我试图用来遍历对象的代码
const juegos = await api.juegosPublicos()
if (juegos.error && typeof juegos.mensaje === 'string') {
console.error(mensaje)
return
}
Object.keys(juegos).forEach((juegoId:string) => {
console.log(juegos[juegoId]) // <- this is the line than generates the error
})
如何正确遍历打字稿中的对象
答案 0 :(得分:2)
开始:我不明白您为什么要检查juegos.error
的真实性。如果juegos
是APIError
,则此值为true
或false
;如果它是false
,那么您就不应检查其真实性,因为您会错误地认为它不是APIError
,而是它。如果juegos
是ListadoJuegosPublicos
,则此值为undefined
或对象;如果它是一个对象,那么您不应该检查真实性,因为您会错误地认为它是APIError
,而不是它。
接下来,我将仅保留typeof juegos.mensaje === 'string'
检查,因为这足以确定某物是否为APIError
。
显然,即使 you 理解typeof juegos.mensaje !== 'string'
暗示juegos
是ListadoJuegosPublicos
,但编译器也不理解 ,并且不对juegos
执行基于control flow analysis的缩小。也就是说,对juegos.mensaje
的支票不会充当juegos
上的type guard。
看起来ListadoJuegosPublicos
的问题是index signature,如果是,则microsoft/TypeScript#17960的问题是相关的开放GitHub问题,列为错误。如果是这样,看来很快就不会解决。
无论如何,当编译器无法将某些代码识别为类型保护时,您可以选择将该代码提取到自己的user-defined type guard function中。例如:
function isAPIError(x: APIError | ListadoJuegosPublicos): x is APIError {
return (typeof x.mensaje === 'string');
}
这与以前相同,但被显式标记为类型防护函数,该函数接受名为x
的值并返回一个boolean
值,该值确定编译器是否对待{{1} }作为x
。现在,我们在原始代码中调用类型保护功能:
APIError
,并且有效。在 if (isAPIError(juegos)) {
console.error(juegos.mensaje)
return
}
Object.keys(juegos).forEach((juegoId: string) => {
console.log(juegos[juegoId]) // okay now
});
语句之后,编译器现在认识到return
必须是juegos
并允许字符串索引迭代。
答案 1 :(得分:0)
您的代码可以正常工作。实际问题在于下面的行
async juegosPublicos ():Promise<APIError|ListadoJuegosPublicos>
您可以做的一件事是将type替换为any:
async juegosPublicos ():Promise<any>