RogueGingerz
RogueGingerz

Reputation: 188

Unable to render Component dynamically through Object.entries

I'm trying to reduce my code and render a series of MUI rows through a loop and Object.entries. Though each time that I try to extract the value of a sperate Object, I get this

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Chalk'.   No index signature with a parameter of type 'string' was found on type 'Chalk'. rowLabels and chalk keys match.

const ConfigureRowValue = () => {
  const rowLabels = {
    sling: "Load",
    bump: "Bump Priority",
    equipment: "Key Equipment",
    w: "Key W",
    notes: "Notes",
  };
  for (const [key, value] of Object.entries(rowLabels)) {
    return (
      <>
        <ChalkCardDataRow label={`${value}`} value={`${chalk[key]}`} />
      </>
    );
  }
};

//...

type ChalkCardDataRowProps = {
  label: string,
  value: string | null,
};

export const ChalkCardDataRow = ({ label, value }: ChalkCardDataRowProps) => {
  return (
    <TableRow>
      <TableCell style={{ borderBottom: "none" }}>{label}:</TableCell>
      <TableCell align={"right"} style={{ borderBottom: "none" }}>
        <Typography color="grey">{value ?? "-"}</Typography>
      </TableCell>
    </TableRow>
  );
};

If I explicitly insert the component multiple times it works but causes too much code duplication. i.e:

<ChalkCardDataRow label={"Sling Load"} value={chalk.sling} />
<ChalkCardDataRow label={"Bump Priority"} value={chalk.bump} />

Upvotes: 1

Views: 77

Answers (1)

ghybs
ghybs

Reputation: 53280

Unfortunately Object.entries return type gives the keys as string, instead of keyof object. See ms/TS#12253 for explanations on this design choice.

The usual workaround is to use a type assertion in this case, since you are sure that both objects have the same keys: chalk[key as keyof typeof rowLabels]

Playground Link


Another solution would be to use ts-extras/objectEntries:

A strongly-typed version of Object.entries().

import {objectEntries} from 'ts-extras';

for (const [key, value] of objectEntries(rowLabels)) {
  result.push(
    <>
      <ChalkCardDataRow
        label={`${value}`}
        value={`${chalk[key]}`} // Okay
      />
    </>
  );
}

Playground Link

Upvotes: 1

Related Questions