元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型 - Phaser

Posted

技术标签:

【中文标题】元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型 - Phaser【英文标题】:Element implicitly has an 'any' type because expression of type 'string' can't be used to index type - Phaser 【发布时间】:2020-10-04 05:43:59 【问题描述】:

我知道有人问过这个问题,但仍然无法为我的情况找到解决方案。

我有一个文件,我在其中定义了某些值,然后我要循环遍历它们。我在这部分代码中得到错误

preloadImages()
    this.load.setPath("./assets/images");
    for (const key in STATIC.IMAGES) 
        if (STATIC.IMAGES.hasOwnProperty(key)) 
            this.load.image(STATIC.IMAGES[key], STATIC.IMAGES[key]);                
        
    

投诉来自 STATIC.IMAGES[key] 调用。 而 STATIC 来自一个带有

的文件
export const STATIC = 

SCENES: 
    LOAD: "LOAD",
    MENU: "MENU"
,

IMAGES: 
    MENU_BG :"bg.png",
    MENU_TITLE: "title.png",
    MENU_PLAY: "play.png",
    MENU_SETTINGS: "settings.png",
    MENU_CREDITS: "credits.png",
    MENU_SPEAKER: "speaker.png",
    MENU_SPEAKER_MUTE: "speaker_mute.png"
,

SPRITES: 
    LOOP:  
        name: "loop.png",
        size: 64
    
,

AUDios: 
    BG_MUSIC: "airtone.mp3",
    POP: "pop.mp3",
    WOOSH: "woosh.mp3"
;

我不确定我理解为什么会发生这种情况以及如何解决它。

【问题讨论】:

【参考方案1】:

让我们将其缩减为minimal, reproducible example。随意将下面的obj 替换为您的STATIC.IMAGES;无论哪种方式都是相同的解释:

let obj =  a: "hey", b: "you", c: "guys" ;

for (const k in obj) 
  console.log(obj[k].toUpperCase()); // error!
  /* Element implicitly has an 'any' type because expression of type 
  'string' can't be used to index type ' a: string; b: string; c: string; '. */

这里我们有一个带有三个键的对象obj。我们尝试使用for..in 循环遍历这些键,我们得到一个错误,您不能使用k 来索引obj。为什么?这不是for..in 循环的意义吗?


这里的问题是 TypeScript 中的对象类型是 openextendible,而不是 closedexact .您可以在 TypeScript 中为对象添加额外的属性,而不会违反其类型。这在某些情况下非常有用:它允许您通过添加属性来扩展接口和子类。但在其他情况下,这很痛苦:

编译器将obj 视为a: string, b: string, c: string 类型的值。由于这种类型不精确,当您执行 for (const k in obj) 时,编译器知道 k 将采用值 "a""b""c",但它不会知道这些是唯一可能的值:

let hmm =  a: "hey", b: "you", c: "guys", d: 12345 ;
obj = hmm; // no error!

obj = hmm 中没有错误,因为值 hmm 匹配 a: string, b: string, c: stringd 属性不违反类型。因此,就编译器所知,for (const k in obj) 将枚举 "a""b""c"谁知道还有哪些 string。因此,k 的类型不是keyof typeof obj。它只是string

使用string 类型的键索引a: string, b: string, c: string 是不安全的。事实上,将hmm 分配给obj,调用(12345).toUpperCase() 时会出现运行时错误。所以编译器警告你是正确的,如果不是很有用的话。

请参阅microsoft/TypeScript#35847 以获取此问题答案的“官方”版本。另请参阅Why doesn't Object.keys() return a keyof type in TypeScript?,这是同一个问题,除了使用Object.keys(obj).forEach(k => ...) 而不是for (const k in obj) ...... 并且它具有相同的答案。

如果曾经引入确切的类型,那么也许这个问题就会消失。对此有一个功能请求:microsoft/TypeScript#12936。但看起来这不会很快发生。


那么,现在可以做些什么呢?好吧,如果我们确定obj 不会有任何编译器不知道的额外键,我们可以把它当作一个精确的类型来对待,只是告诉编译器不要担心它。这种“告诉编译器”的形式是type assertion:

for (const k in obj) 
  console.log(obj[k as keyof typeof obj].toUpperCase()); // okay

这里,k as keyof typeof obj 是类型断言。我们必须小心不要这样对编译器撒谎,但只要我们小心就可以了。


为了完整起见,您还可以在循环外声明 k 并为其指定更窄的类型;这在类型安全方面等价于类型断言:

let k: keyof typeof obj;
for (k in obj) 
  console.log(obj[k as keyof typeof obj].toUpperCase()); // okay


好的,希望对您有所帮助;祝你好运!

Playground link to code

【讨论】:

以上是关于元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型 - Phaser的主要内容,如果未能解决你的问题,请参考以下文章

元素隐式具有“任何”类型,因为字符串类型的表达式 | number 不能用于索引类型

元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型 - Phaser

元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型 React Typescript

嵌套对象 -> 元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型

TS7053:元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引类型“用户经济”

TypeScript - ts(7053):元素隐式具有“任何”类型,因为“字符串”类型的表达式不能用于索引