为什么用 Record 类型注释此对象会删除智能感知?

问题描述 投票:0回答:2

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

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)
  }
};

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

import { sprites } from "../data/sprites";

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

let player = sprites.player;

然后,当我输入

sprites.

时,我没有得到 Intellisense(代码完成)

但是,我注意到,如果我从

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

但是,我相信我需要这个注释,因为我的一个函数只采用

ISprite
类型,而且我不想让它采用
any

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

typescript record code-completion strong-typing
2个回答
5
投票

这样做是因为

Record<string, ISprite>
可以将 any 字符串作为键。 UI 无法提示每个字符串。

您可以通过使用具有这些命名属性的类型和

monster
之间的交集,为 UI 提供更多信息,使其显示
player
Record<string, ISprite>
以便自动完成(但请继续阅读,您可能不需要):

export let sprites: {monster: ISprite, player: ISprite} & 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)
  }
};

游乐场链接

但是

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

没关系。根本没有任何类型注释,对象的

monster
player
属性上的值与
ISprite
兼容,因此您可以将它们传递给需要
ISprite
的函数。 TypeScript 的类型系统是structural(基于对象的形状),而不是nominal(基于类型的名称),因此它很乐意接受任何对象作为
ISprite
,只要它具有兼容的所有必要属性类型。这很好用,例如:

export let sprites = {
    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)
    }
};

function example(sprite: ISprite) {
    console.log(sprite);
}

example(sprites.monster); // <=== Perfectly happy

游乐场链接

如果您想要类型名称,或者在

ISprite
中编写更多条目时提示
sprites
的成员,您可以给自己一个函数:

makeSprite(sprite: ISprite) {
    return sprite;
}

它看起来像是什么都不做,而且确实是在运行时。 (别担心,它并不贵)。但在创作时,它可以让你这样做:

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

添加条目时,在为

ISprite
编写精灵参数时,系统会提示您输入
makeSprite
中的属性名称。


0
投票

如果您使用的是 TypeScript 4.9 + ,使用

statisfies
关键字似乎可以解决这个问题。 游乐场链接

您在使用对象和编辑对象时都会获得智能感知。

© www.soinside.com 2019 - 2024. All rights reserved.