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