我正在构建一个工具来判断网络上的状态.环境文件有一堆各种项目(例如虚拟机、DB等)的地址.dev的类型如下:

export type EnvDefinition = {
  'DetailedErrors': boolean,
  'Logging': LogDefinition,
  'SystemElementGroups': {
    'VMs': SystemElement[],
    'Applications': SystemElement[],
    'Databases': SystemElement[],
  },
}

SytemElement只是定义IP地址和其他所需内容的另一种类型.

当我从json文件加载dev数据时,我将其转换为这样:

import envData from '../development.json';
const data: EnvDefinition = envData;

然后我try 像这样访问单个组数据:

const assetTypes = ['VMs', 'Applications', 'Databases'];
for (const assetType of assetTypes) {
    const connectStrings = data.SystemElementGroups[assetType];

无论我try 什么,我都会收到TS错误:TS7053: Element implicitly has an any type because expression of type string can't be used to index type

如何定义它以便在循环中访问SystemElementGroups

谢谢

推荐答案

线路中

const assetTypes = ['VMs', 'Applications', 'Databases'];

你还没有像const assertTypes: XXX =这样的annotated个. 因此,TypScript必须将assetTypes的类型从您初始化时使用的array literal中进行101.它推断的类型将在所有后续使用assetTypes变量时参考.

有很多可能的类型适用于特定的数组文字. 它可以是超级一般的东西,比如the unknown type,也可以是非常具体的东西,比如由字符串literal types["VMs", "Applications", "Databases"]组成的tuple type. 或者介于两者之间的任何内容,比如Array<string | number> | boolean. 它基于启发式规则进行 Select ,这些规则在各种现实世界的代码中都很有效,但这些规则并不总是满足每个人的需求.

如果数组文字中包含字符串文字,则TypScript将类型推断为an array(满分string):即Array<string>或等效的string[]. 这允许您在其中添加push()个新字符串值,或者添加sort()个字符串值,等等.但这意味着编译器甚至不会try 跟踪数组中的which个字符串值或它们所在的位置. 同样,这对于许多用例都很有效.

但不幸的是,这意味着TypScript不知道代码

for (const assetType of assetTypes) {
    const connectStrings = data.SystemElementGroups[assetType];

是安全的您正在用string类型的assetType索引到data.SystemElementGroups,该assetType根本可以是任何字符串,其中大部分不知道是键.这就是错误消息所说的.

问题是assetTypes的类型太一般,无法满足您的需求.


如果您想让编译器相信assetTypes只包含EnvDefinitionSystemElementGroups属性的键,请使用could annotate assertTypes:

const assetTypes: Array<keyof EnvDefinition['SystemElementGroups']> =
  ['VMs', 'Applications', 'Databases'];
for (const assetType of assetTypes) {
  const connectStrings = data.SystemElementGroups[assetType]; // okay
}

这可行,但有点冗长.

另一种方法是使用a const assertion来告诉编译器由数组字面量初始化的数组根本不会更改.它将永远是一个由三个元素组成的数组,其类型是初始化元素的字符串字面量类型,并且它们将按照初始化时的完全顺序:

const assetTypes = ['VMs', 'Applications', 'Databases'] as const;
// const assetTypes: readonly ["VMs", "Applications", "Databases"]

现在assetTypes的类型非常具体.你不能在上面添加push()个随机字符串,或者sort()个字符串,或者写assetTypes[0]="random".这可能比您关心的更具体,但用as const很容易做到.现在编译器有足够的信息来知道assetTypes的每个元素都是data.SystemElementGroups的有效密钥:

for (const assetType of assetTypes) {
  const connectStrings = data.SystemElementGroups[assetType]; // okay
}

Playground link to code

Javascript相关问答推荐

验证嵌套 colored颜色 代码的结果

以逗号分隔的列表来数组并填充收件箱列表

添加/删除时React图像上传重新渲染上传的图像

JS生成具有给定数字和幻灯片计数的数组子集

微软Edge Select 间隙鼠标退出问题

从PWA中的内部存储读取文件

类型脚本中只有字符串或数字键而不是符号键的对象

调用removeEvents不起作用

我不知道为什么setwritten包装promise 不能像我预期的那样工作

TypeScript索引签名模板限制

Regex结果包含额外的match/group,只带一个返回

制作钢琴模拟器,并且在控制台中不会执行或显示该脚本

可更改语言的搜索栏

如何在Svelte中从一个codec函数中调用error()?

使用getBorbingClientRect()更改绝对元素位置

基于props 类型的不同props ,根据来自接口的值扩展类型

Webpack在导入前混淆文件名

在css中放置所需 colored颜色 以填充图像的透明区域

AddEventListner,按键事件不工作

Pevent触发material 用户界面数据网格中的自动保存