Home > other >  How to re order a typescript object/StringMap to have the last element first
How to re order a typescript object/StringMap to have the last element first

Time:07-27

I'm working in a .tsx file and am completely new to TS/React. I am trying to add a key/value pair to a StringMap at the very first index.

I have some code below that:

takes in the StringMap 'stats',

goes through each row and extracts clan from a string,

adds each clan to 'clans' (string[]),

creates a new stats map with clans 'statsWithClans'

function handlePlayerStatssWindow(stats: StringMap<string>) 
{
const rawFields = Object.keys(stats).map((key, i) => (
    <div key={i}>
        {key}: {stats[key]}
    </div>
));

var clans: string[] = [];

for (const [key, value] of Object.entries(stats)) 
{
    const roles: string[] = value.split(',');
    for(const role of roles)
    {
        if(role.includes('clan='))
        {
            clans.push(role.replace('clan=',''));
        }
    }
}

const statsWithClans = {...stats};
statsWithClans.clans = clans.toString();

// const statsWithClans = {clans: (clans.toString()), ...stats};

const formattedFields = Object.keys(statsWithClans).map((key, i) => (
    <div key={i}>
        {key}: {statsWithClans[key]}
    </div>
));
}

The code works and outputs something like:

Name: Jeff
Class: Mage
Clans: Clan1, Clan2

If I try creating the map with clans at the start like so

const statsWithClans = {clans: (clans.toString()), ...stats};

Typescript complains saying:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ groups: string; }'. No index signature with a parameter of type 'string' was found on type '{ groups: string; }'.ts(7053)

and 'statsWithClans[key]' is highlighted

StringMap defintion

export default interface StringMap<T> {
    [index: string]: T;
}

CodePudding user response:

This is a known issue in TypeScript, see microsoft/TypeScript#27273. If you do spread an object with an index signature into an object literal with other properties, the compiler silently drops the index signature. Since your StringMap<T> type has an index signature, that is what's happening:

const oops = { clans: (clans.toString()), ...stats };
// const oops: {  clans: string; }

The index signature on stats is forgotten, and the new variable has type {clans: string}, with no index signature. And you can't index into a value with an arbitrary string key unless that value has a string index signature.

The easiest way to deal with this in your example code is to explicitly annotate the type of your stats variable:

const statsWithClans: StringMap<string> =
  { clans: (clans.toString()), ...stats }; // okay

Now statsWithClans is of the expected type and the rest of your code behaves as desired:

const formattedFields = Object.keys(statsWithClans).map((key, i) => (
  <div key={i}>
    {key}: {statsWithClans[key]} // okay
  </div>
));

Playground link to code

  • Related