为什么用 Record 类型注释此对象会删除 Intellisense?

Rya*_*hel 2 record strong-typing code-completion typescript

我正在创建一个如下所示的数据文件:

interface ISprite {
  textureName: string,
  frame: Frame,
  origin: Vec2,
  zIndex?: number
}

export let sprites: Record<string, ISprite> = {
  monster: {
    textureName: "monster",
    frame: new Frame(0, 0, 32, 41),
    origin: new Vec2(16, 28),
    zIndex: -1
  },
  player: {
    textureName: "player",
    frame: new Frame(0, 0, 32, 32),
    origin: new Vec2(15, 32)
  }
};
Run Code Online (Sandbox Code Playgroud)

如果我然后尝试从另一个文件导入此数据文件,如下所示:

import { sprites } from "../data/sprites";
Run Code Online (Sandbox Code Playgroud)

然后尝试访问这样的属性:

let player = sprites.player;
Run Code Online (Sandbox Code Playgroud)

然后我在输入时没有得到 Intellisense(代码完成)sprites.

然而,我注意到,如果我Record<string, ISprite>sprites变量声明中删除注释,我确实会获得智能感知。

但是,我相信我需要这个注释,因为我的函数之一只接受ISprite类型,并且我不想让它接受any.

是否可以在保持强类型的同时还具有代码完成功能?

T.J*_*der 5

这样做是因为Record<string, ISprite>可以有任何字符串作为键。UI 无法提示每个字符串。

\n

您可以通过使用具有这些命名属性的类型monsterplayerRecord<string, ISprite>自动完成(但请继续阅读,您可能不需要):

\n
export let sprites: {monster: ISprite, player: ISprite} & Record<string, ISprite> = {\n// \xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92\xe2\x88\x92^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  monster: {\n    textureName: "monster",\n    frame: new Frame(0, 0, 32, 41),\n    origin: new Vec2(16, 28),\n    zIndex: -1\n  },\n  player: {\n    textureName: "player",\n    frame: new Frame(0, 0, 32, 32),\n    origin: new Vec2(15, 32)\n  }\n};\n
Run Code Online (Sandbox Code Playgroud)\n

游乐场链接

\n

然而

\n
\n

我相信我需要这个注释,因为我的函数之一只采用 ISprite 类型。

\n
\n

没关系。根本没有任何类型注释,对象的值monsterplayer属性与 兼容ISprite,因此您可以将它们传递给期望的函数ISprite。TypeScript 的类型系统是结构化的(基于对象的形状),而不是名义的(基于类型的名称),因此它很乐意接受任何对象作为ISprite只要它具有兼容类型的所有必要属性。这工作得很好,例如:

\n
export let sprites = {\n    monster: {\n      textureName: "monster",\n      frame: new Frame(0, 0, 32, 41),\n      origin: new Vec2(16, 28),\n      zIndex: -1\n    },\n    player: {\n        textureName: "player",\n        frame: new Frame(0, 0, 32, 32),\n        origin: new Vec2(15, 32)\n    }\n};\n\nfunction example(sprite: ISprite) {\n    console.log(sprite);\n}\n\nexample(sprites.monster); // <=== Perfectly happy\n
Run Code Online (Sandbox Code Playgroud)\n

游乐场链接

\n

如果您想要类型名称,或者ISprite在您编写更多条目时提示其成员sprites,您可以给自己一个函数:

\n
makeSprite(sprite: ISprite) {\n    return sprite;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

看起来像什么都不做,运行时是\xc2\xa0\xe2\x80\x94。(别担心,它并不贵)。但在创作时,它允许您执行以下操作:

\n
export let sprites = {\n    monster: makeSprite({\n      textureName: "monster",\n      frame: new Frame(0, 0, 32, 41),\n      origin: new Vec2(16, 28),\n      zIndex: -1\n    }),\n    player: makeSprite({\n        textureName: "player",\n        frame: new Frame(0, 0, 32, 32),\n        origin: new Vec2(15, 32)\n    })\n};\n
Run Code Online (Sandbox Code Playgroud)\n

当您添加条目时,系统会提示您ISprite输入精灵参数时的属性名称makeSprite属性名称。

\n