10

我正在尝试使用 reduce 和 Typescript 来达到传入消息的总数。我对如何添加索引签名感到困惑。我不断收到错误消息:“元素隐式具有 'any' 类型,因为类型 '{}' 没有索引签名。” 在变量 newArray 和 counts[k] 上。我已经阅读了几个类似的问题,但还没有弄清楚如何将它们应用于我的特定场景。我是 JavaScript 和 TypeScript 的新手。

这是我的数组:

        var data = [
        { time: '9:54' }, 
        { time: '9:54' },
        { time: '9:54' },
        { time: '9:55' }, 
        { time: '9:55' },
        { time: '9:55' },
        { time: '9:55' },
        { time: '9:56' }, 
        { time: '9:56' },
        { time: '9:56' },
        { time: '9:56' },
        { time: '9:57' }, 
        { time: '9:57' },
        { time: '9:57' },
        { time: '9:57' },
        { time: '9:57' }
    ];

这就是我需要我的数组在图表图中使用的方式:

        var dataWithCounts = [
        { time: '9:54', messages: 3 }, 
        { time: '9:55', messages: 4 }, 
        { time: '9:56', messages: 4 }, 
        { time: '9:57', messages: 5 }
    ];

在这个 Stack Overflow 问题的“只是一个学生”的回答的帮助下:Group and count values in an array ,我有以下内容。

        var counts = data.reduce((newArray, item) => {
           let time = item.time;
           if (!newArray.hasOwnProperty(time)) {
               newArray[time] = 0;
           } 
           newArray[time]++;
           return newArray;
        }, {});

        console.log(counts);

        var countsExtended = Object.keys(counts).map(k => {
           return { time: k, messages: counts[k] };
       });

       console.log(countsExtended);

我在哪里以及如何声明索引签名?以下是我尝试过的各种方法。

  • let newArray: { [time: string] };并收到重复标识符错误。

  • 将字符串添加到参数var counts = data.reduce((newA:string, item)会给我一个错误“元素隐式具有'任何'类型,因为索引表达式不是'数字'类型。”

  • 添加newA[time].toString()给我错误,“赋值表达式的左侧必须是变量或属性访问。”

4

5 回答 5

15

调用中的累加器类型.reduce几乎肯定是问题所在。由于它只是作为 给出{},这就是它的类型被推断为,并且该类型{}没有索引签名。您可以通过强制转换初始值来解决此问题,以便它包含签名:

var counts = data.reduce((newArray, item) => {
    let time = item.time;
    if (!newArray.hasOwnProperty(time)) {
        newArray[time] = 0;
    } 
    newArray[time]++;
    return newArray;
}, {} as {[key: string]: any}); // <-- note the cast here

我给出了索引签名类型any,但您可能希望针对您的特定情况使其更具体。

于 2018-02-13T18:23:51.243 回答
4

您的数组的正确类型是:

Array<{time: string}>

或者:

{time: string}[]

或者:

{[key: number]: {time: string}}
于 2018-02-13T18:29:21.430 回答
1

回答原始问题

主要的警告是reduce累加器值没有正确输入。

原始代码:

const result = data.reduce(someLogicCallback, {})

需要通过以下方式进行:

const accumulator: {[key: string]: number} = {}
const result = data.reduce(someLogicCallback, accumulator)

其他可能的注意事项

这部分可能对后来偶尔的谷歌用户有所帮助。

我来这里是为了解决类似的问题,但在我的情况下,我有一个已经预定义类型的对象

typeof someObject // predefinedType

type predefinedType = {
  someKey: number;
  otherKey: number;
}

index signature is missing in type predefinedType当我尝试从该对象中提取条目时出现错误

const entries = Object.entries<number>(someObject);

显而易见的解决方案是进行类型断言

type TypedIndexObj = {[key: string]: number}
const entries = Object.entries<number>(someObject as TypedIndexObj);

但这太严格了,因为它总是会断言someObjectas的值类型number可能会随着时间而改变。

我想出的添加此类对象的索引类型的最佳方法是使用keyof语法

type TypedIndexObj = {[key in keyof typeof someObject]:(typeof someObject)[key]}
const entries = Object.entries<number>(someObject as TypedIndexObj);

参考:原始问题的更正代码

这是原始问题中代码的完全键入的更正版本:

const accumulator: {[key: string]: number} = {}

const counts = data.reduce((_accumulator, item) => {
  const time = item.time;
  // no error on the next line
  if (!_accumulator.hasOwnProperty(time)) {
      _accumulator[time] = 0;
  } 
  _accumulator[time]++;
  return _accumulator;
}, accumulator);

const countsExtended = Object.keys(counts).map(k => {
    return { time: k, messages: counts[k] };
});
于 2021-06-01T18:16:34.897 回答
0

如果我理解你,你需要为对象创建接口......

interface counts_t{
    time?: string,
    messages?: number
}

var data: counts_t[] = [
    { time: '9:54' }, 
    { time: '9:55' }, 
    { time: '9:56' }, 
    { time: '9:57' }
];

    var counts = data.reduce((newArray:counts_t, item:counts_t) => {
       let time = item.time;
       if (!newArray.hasOwnProperty(time)) {
           newArray[time] = 0;
       } 
       newArray[time]++;
       return newArray;
    }, {});

    console.log(counts);

    var countsExtended: counts_t[] = Object.keys(counts).map(k => {
       return { time: k, messages: counts[k] };
    });

   console.log(countsExtended);
于 2018-02-13T18:20:43.503 回答
0

您必须添加具有索引签名的类型。前任。

const myObj: {[key: string]: string} = {
  someProperty: 'someValue',
};

告诉 Typescript这个{[key: string]: any}obj 有一个字符串类型的索引签名。

于 2020-08-19T18:50:28.683 回答