【问题标题】:Getting error while referencing the type as index将类型引用为索引时出错
【发布时间】:2020-06-14 12:46:15
【问题描述】:

我有一个具有以下结构的对象数组

let sampleData = [
    { valueObj: { High: 4, Low: 5,  Medium: 7 } , time: "1571372233234" , sum: 16 },
    { valueObj: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},
    { time: "14354545454", sum: 0},
    { time: "14354545454", sum: 0} }
];

我需要获取数组内每个对象中的每个键并从中形成一个数组。基本上基于所有对象中存在的键进行分组。如果对象没有“值”,它应该在 val1,val2,val3 中返回 0。

result = [
  { name: 'High', data: [4, 5, 0, 0] }, 
  { name: 'Medium', data: [5, 3, 0, 0] }, 
  { name: 'Low', data: [7, 1, 0, 0] }
];

这里我传递了一个字符串,它将在 reduce 中使用。我收到此错误 any cannot be used as index 每当我传递将在 reduce 函数中使用的动态字符串时每当启用打字稿时。

代码运行良好,但是在我升级到最新的 TS 后,它抛出错误并且无法编译

有人可以帮我吗?

我尝试了以下方法:

const sampleData = [{ valueObj: { High: 4, Low: 5,  Medium: 7 }, time: "1571372233234", sum: 16 }, { valueObj: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234", sum: 9 }, { time: "14354545454", sum: 0 }, { time: "14354545454", sum: 0 }];

const keys = ['High', 'Low', 'Medium'];

function formResult(sampleData, prop, keys){
  let grouped = sampleData.reduce((r, { [prop]: values = {} } = {}) => {
    r.forEach(({ name, data }) => data.push(values[name] || 0));       
    return r;
  }, keys.map(name => ({ name, data: [] })));
  console.log(grouped);
}

formResult(sampleData,"valueObj", keys);

【问题讨论】:

    标签: javascript typescript ecmascript-6 ecmascript-5 ecmascript-2016


    【解决方案1】:

    reduce 与带有Typescript 的动态键一起使用可能很难看,并且在创建单个对象时是arguably not appropriate even in Javascript。考虑创建将数据放入循环外部的对象 - 其属性是名称(高等)并且值是数字数组的对象。在每次迭代时推送到数字数组(如果属性不存在则推送 0),如果需要,首先使用数组创建属性。循环之后,把对象变成对象数组:

    // compliant with noImplicitAny and strict options
    type DataItem = {
        time: string;
        sum: number;
        valueObj?: {
            High: number;
            Medium: number;
            Low: number;
        }
    };
    const sampleData: DataItem[] = [
        { valueObj: { High: 4, Low: 5,  Medium: 7 } , time: "1571372233234" , sum: 16 },
        { valueObj: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},
        { time: "14354545454", sum: 0},
        { time: "14354545454", sum: 0}
    ];
    const keys = ['High', 'Low', 'Medium'] as const;
    const grouped = {} as { [key: string]: number[] };
    for (const item of sampleData) {
        for (const key of keys) {
            if (!grouped[key]) {
                grouped[key] = [];
            }
            grouped[key].push(item.valueObj ? item.valueObj[key] : 0);
        }
    }
    const output = Object.entries(grouped).map(([name, data]) => ({ name, data }));
    

    编译输出:

    "use strict";
    const sampleData = [
        { valueObj: { High: 4, Low: 5, Medium: 7 }, time: "1571372233234", sum: 16 },
        { valueObj: { High: 5, Low: 3, Medium: 1 }, time: "1571372233234", sum: 9 },
        { time: "14354545454", sum: 0 },
        { time: "14354545454", sum: 0 }
    ];
    const keys = ['High', 'Low', 'Medium'];
    const grouped = {};
    for (const item of sampleData) {
        for (const key of keys) {
            if (!grouped[key]) {
                grouped[key] = [];
            }
            grouped[key].push(item.valueObj ? item.valueObj[key] : 0);
        }
    }
    const output = Object.entries(grouped).map(([name, data]) => ({ name, data }));
    console.log(output);

    如果valueObj 键是动态的,它会变得更丑陋。我能想到的最好的办法是,当迭代一个数组项时,如果它有自己的对象键属性,那么断言数组项的类型是{ [possibleKeyForObj: string]: { [key: string]: number } },允许您访问嵌套属性:

    const formResult = (
        sampleData: object[],
        possibleKeyForObj: string,
        keys: string[],
    ) => {
        const grouped = Object.fromEntries(keys.map(key => [key, []]));
        for (const item of sampleData) {
            for (const key of keys) {
                grouped[key].push(
                    item.hasOwnProperty(possibleKeyForObj)
                        ? (item as { [possibleKeyForObj: string]: { [key: string]: number } })[possibleKeyForObj][key]
                        : 0,
                );
            }
        }
        const output = Object.entries(grouped).map(([name, data]) => ({ name, data }));
        console.log(output);
    };
    
    formResult(
        [
            { valueObj: { High: 4, Low: 5, Medium: 7 }, time: '1571372233234', sum: 16 },
            { valueObj: { High: 5, Low: 3, Medium: 1 }, time: '1571372233234', sum: 9 },
            { time: '14354545454', sum: 0 },
            { time: '14354545454', sum: 0 },
        ],
        'valueObj',
        ['High', 'Low', 'Medium'],
    );
    

    【讨论】:

    • 需要让 TS 了解对象可以具有什么样的属性和值(即字符串键,具有数字数组的值)。没有它,当您尝试分配其属性时会遇到错误。
    • 我希望“valueObj”是动态的,可以传递给函数。就像问题一样, formResult(sampleData,"valueObj", keys);想让解决方案有点通用
    • 让属性名称是动态的并且正确地进行所有类型检查是很困难的。我认为有一种优雅的方法可以使用类型参数来做到这一点,但我无法弄清楚 ATM,我正在拼凑不太优雅的方法......
    • 查看编辑。对于更优雅的解决方案,我认为您最好的选择可能是更改输入数据结构,以便属性位于可预测的位置。例如,不是{ valueObj: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},,可能是{ time: "1571372233234" , sum: 9, dynamicObj: { label: 'valueObj', obj: { High: 5, Low: 3, Medium : 1 } },其中键名是always dynamicObj
    • 这使得打字更容易管理。 type Item = { time: string, sum: number, dynamicObj?: { label: string, obj: { [key: string]: number } } }; 和输入数组只是一个 Item[],看起来有点不安全的类型断言是不必要的。
    【解决方案2】:

    函数没有返回grouped。这可能是问题

    const sampleData = [{
      valueObj: {
        High: 4,
        Low: 5,
        Medium: 7
      },
      time: "1571372233234",
      sum: 16
    }, {
      valueObj: {
        High: 5,
        Low: 3,
        Medium: 1
      },
      time: "1571372233234",
      sum: 9
    }, {
      time: "14354545454",
      sum: 0
    }, {
      time: "14354545454",
      sum: 0
    }];
    
    const keys = ['High', 'Low', 'Medium'];
    
    function formResult(sampleData, prop, keys) {
      return sampleData.reduce((r, {
        [prop]: values = {}
      } = {}) => {
        r.forEach(({
          name,
          data
        }) => data.push(values[name] || 0));
        return r;
      }, keys.map(name => ({
        name,
        data: []
      })));
    
    }
    
    console.log(formResult(sampleData, "valueObj", keys));

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-18
      • 2021-08-13
      • 1970-01-01
      • 2016-01-26
      • 1970-01-01
      • 2014-01-09
      • 2010-11-23
      • 1970-01-01
      相关资源
      最近更新 更多