当前位置: 首页 > 知识库问答 >
问题:

遍历compex对象以修改Typecript中的所有值

冯阳成
2023-03-14

我有一个看起来像这样的打字稿界面:

interface IPageConfig {
    fooSection?: IFooSectionUrlMap;
    barSection?: IBarSectionUrlMap;
    blaSection?: IBlaSectionUrlMap;
}

interface IFooSectionUrlMap {
    oneUrl: string;
    twoUrl: string;
    threeUrl: string;
}

interface IBarSectionUrlMap {
    fourUrl: string;
    fiveUrl: string;
    sixUrl: string;
}

interface IBlaSectionUrlMap{
    sevenUrl: string;
    eightUrl: string;
    nineUrl: string;
}

我想做的是遍历对象上的每个URL——在每个属性中——并通过在每个URL前面加上/将它们从相对URL更改为绝对URL。

我尝试使用Object.keys.forEach()和Object.entries.forEach()从我遇到的一些文章中,我尝试使用...在循环中将事物定义为键。在 TS 抱怨之前,它总是能很好地通过第一级。它抱怨同样的事情:

'for… in'语句的左侧必须是'string'或'any'. ts类型(2405)

我在这里做错了什么?下面是代码:

typescript prettyprint-override">function convertToRelativeUrls(config: IPageConfig) {
    let sectionName: keyof IPageConfig;
    for (sectionName in config) {
        if (sectionName.endsWith('Section')) {
            let section = config[sectionName];
            if (section) {

                // If I hover over it, propName has a type of never
                let propName: keyof typeof section;

                // Right here is where TS complains -- propName
                for (propName in section) {
                    if (propName && section && section[propName]) {

                        // When I try setting it, the right-hand side is fine.
                        // The left-hand side says 
                        // "Type 'string' is not assignable to type 'never'"
                        section[propName] = '/' + section[propName];
                    }
                }
            }
        }
    }
}

编辑:我的函数中的错别字。应该是<代码>。endsWith('Section'),而不是< code >。endsWith('UrlMap')。我已经修复了原始版本,但我把它留在这里,所以呼吁它的评论仍然有意义。

共有1个答案

周和安
2023-03-14

您可以通过修改类型和函数的某些方面来解决这个问题。

要使这种方法起作用,您需要使用类型别名而不是接口,以便在声明后无法将其他字段添加到您的类型中:这会通知编译器它们不是开放/可变的。

除了前面的TS手册链接之外,您还可以看到这些链接以获取更多信息:1、2、3

对于每个接口,您都可以这样重写:

// before
interface IFooSectionUrlMap {
  oneUrl: string;
  twoUrl: string;
  threeUrl: string;
}
// after
type IFooSectionUrlMap = {
  oneUrl: string;
  twoUrl: string;
  threeUrl: string;
};

关于从数据派生类型的另一种方法,请参见TS playground链接。

将接口转换为类型别名后,您可以专注于函数。您可以使用一些类型实用程序来创建一个可以分配给IPageConfig的类型,而不是使用IPageConfig作为对象参数的类型

function prefixNestedStrings (obj: Partial<Record<string, Record<string, string>>>): void {
  for (const key in obj) {
    if (!key.endsWith('Section')) continue; // key pattern mismatch

    const objChild = obj[key]; // Record<string, string> | undefined
    if (!objChild) continue; // no value

    for (const key in objChild) {
      if (!key.endsWith('Url')) continue; // key pattern mismatch
      const str = objChild[key];
      if (typeof str !== 'string') continue; // type mismatch
      objChild[key] = `/${str}`;
    }
  }
}

把所有的东西放在一起:

TS游乐场

type IFooSectionUrlMap = {
  oneUrl: string;
  twoUrl: string;
  threeUrl: string;
};

type IBarSectionUrlMap = {
  fourUrl: string;
  fiveUrl: string;
  sixUrl: string;
};

type IBlaSectionUrlMap = {
  sevenUrl: string;
  eightUrl: string;
  nineUrl: string;
};

type IPageConfig = {
  fooSection?: IFooSectionUrlMap;
  barSection?: IBarSectionUrlMap;
  blaSection?: IBlaSectionUrlMap;
};

function prefixNestedStrings (obj: Partial<Record<string, Record<string, string>>>): void {
  for (const key in obj) {
    if (!key.endsWith('Section')) continue; // key pattern mismatch

    const objChild = obj[key]; // Record<string, string> | undefined
    if (!objChild) continue; // no value

    for (const key in objChild) {
      if (!key.endsWith('Url')) continue; // key pattern mismatch
      const str = objChild[key];
      if (typeof str !== 'string') continue; // type mismatch
      objChild[key] = `/${str}`;
    }
  }
}

const pageConfig: IPageConfig = {
  fooSection: {
    oneUrl: 'one',
    twoUrl: 'two',
    threeUrl: 'three',
  },
  barSection: {
    fourUrl: 'four',
    fiveUrl: 'five',
    sixUrl: 'six',
  },
};

prefixNestedStrings(pageConfig);

console.log(pageConfig); // See console: looks good to me

从TS游乐场编译的JS:

function prefixNestedStrings(obj) {
    for (const key in obj) {
        if (!key.endsWith('Section'))
            continue; // key pattern mismatch
        const objChild = obj[key]; // Record<string, string> | undefined
        if (!objChild)
            continue; // no value
        for (const key in objChild) {
            if (!key.endsWith('Url'))
                continue; // key pattern mismatch
            const str = objChild[key];
            if (typeof str !== 'string')
                continue; // type mismatch
            objChild[key] = `/${str}`;
        }
    }
}
const pageConfig = {
    fooSection: {
        oneUrl: 'one',
        twoUrl: 'two',
        threeUrl: 'three',
    },
    barSection: {
        fourUrl: 'four',
        fiveUrl: 'five',
        sixUrl: 'six',
    },
};
prefixNestedStrings(pageConfig);
console.log(pageConfig); // See console: looks good to me
 类似资料:
  • 本文向大家介绍golang遍历时修改被遍历对象的示例详解,包括了golang遍历时修改被遍历对象的示例详解的使用技巧和注意事项,需要的朋友参考一下 前言 很多时候需要将遍历对象中去掉某些元素,或者往遍历对象中添加元素,这时候就需要小心操作了。 对于go语言中的一些注意事项我做了总结和示例,留下点笔记。 遍历切片 1.遍历切片时去掉元素,错误示例: 最终报错panic: runtime error:

  • 问题内容: 如何遍历对象的所有属性?现在,我必须编写新的代码行以打印对象的每个属性 我可以使用foreach循环或任何循环遍历对象的所有属性吗? 像这样 问题答案: 如果这仅用于调试输出,则可以使用以下内容查看所有类型和值。 如果要对输出进行更多控制,可以使用以下命令:

  • 问题内容: 我有一个使用jsoncpp解码JSON字符串的C ++应用程序。我创建了以下函数,但仅向我显示了顶级对象… 如何获取转储整个对象列表的信息? - 功能 - -输入---- -输出- 问题答案: 您可能会遇到一些错误,这些错误似乎与您对递归或JSON的key-> value性质没有很好的了解以及如何与所使用的库相关联。我根本没有测试过此代码,但它应该可以更好地工作。

  • 问题内容: 从Javascript 1.7开始,有一个Iterator对象,它允许这样做: node.js中是否有类似的东西? 现在我正在使用: 但这通过将所有对象密钥存储在中而产生大量开销。 问题答案: 您想要的是对象或数组上的延迟迭代。这在ES5中是不可能的(因此在node.js中是不可能的)。我们最终会得到这个。 唯一的解决方案是找到一个扩展V8的节点模块,以实现迭代器(可能还有生成器)。我

  • 问题内容: 我正在尝试遍历JSON对象以导入数据,即标题和链接。我似乎无法掌握过去的内容。 JSON: 我尝试使用字典: 此代码仅在之前打印信息。( 忽略贾斯汀·比伯的曲目 :) 问题答案: 您加载JSON数据有些脆弱。代替: 您实际上应该这样做: 您不应该将“ JSON对象”视为什么。您所拥有的是清单。该列表包含两个字典。字典包含各种键/值对,所有字符串。当您这样做时,您将要求列表中的第一个字典

  • 问题内容: 我正在运行以下代码,从具有特定列的所有表中提取所有相关的行。外层应该检查该迭代表中是否存在该列。如果没有,它应该完成该迭代并移至下一张表。如果表中有该列,则应检查该表是否将返回任何记录。如果没有要返回的记录,则应结束该迭代并移至下一个表。如果有记录,则应在SSMS中显示它们。 这似乎可行,因为SSMS仅返回带有有效条目的网格。我不明白的是:为什么我仍然会收到这些错误? 编辑 使用建议后