javascriptarraystypescriptindex-signature

How to add index signature in TypeScript


I am trying to use reduce with Typescript to reach a total count of incoming messages. I'm confused on how to add an index signature. I keep getting the error: " Element implicitly has an 'any' type because type '{}' has no index signature." on variables newArray and counts[k]. I have read through several similar questions but have not figured out how to apply them to my specific scenario. I am new to JavaScript and TypeScript.

Here is my array:

        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' }
    ];

This is how I need my array for use in a rechart graph:

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

With the help of 'Just a Student's' answer from this Stack Overflow question: Group and count values in an array , I have the following.

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

Where and how do I declare an index signature? Below are various things I've tried.


Solution

  • The type of your accumulator in the .reduce call is almost certainly the issue. Since it is just given as {}, that's what its type is inferred as, and the type {} doesn't have an index signature. You can fix this by casting your initial value so that it does include a signature:

    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
    

    I gave the index signature type any, but you may want to make it something more specific for your particular case.