Object backet notation in TypeScript with string interpolation from props

I get this error in my code when trying to use a variable in my TSX component (because of the dynamic props coming into the component which are always just a string that matches one of four keys in the “characters” object I import). You can see the structure of the characters object within this error message:

No index signature with a parameter of type ‘string’ was found on type ‘{ design: { name: string; text: string; image: typeof import(“*.svg”); };

I’m not sure how I’m supposed to refer to either characterName[i] OR the incoming ‘character’ prop that I already passed. I can console log these things and get the correct values of course, but TS doesn’t seem to like me trying to use string interpolation or Object Bracket Notation “obj[key]” either to insert the values because it seems to be looking for the actual string “character” or “characterName[i]” instead of the variables those represent…what stupid basic JS/TS mistake am I making here?

The code is as such in the < PointsCard character=”design” /> component:

import React, { useState } from "react";
import styles from "../styles/points.module.css";
import Image from "next/image";
import { characters } from "../utils/characters";

type PointsCardProps = { character: string };
let characterNames = Object.keys(characters);

export const PointsCard = ({ character }: PointsCardProps) => {
  const [points, setPoints] = useState(0);

  let name: string;
  let text: string;
  let image: string;

  for (let i = 0; i < characterNames.length; i++) {
    if (character === characterNames[i]) {
      name = characters[characterNames[i]].name;
      text = characters[characterNames[i]].text;
      image = characters[characterNames[i]].image;
    }
  }

  console.log(characterNames);

  return (
    <div className={styles.card}>
      <Image src={image} width={100} height={100} alt="Design Doctor" />
      <div>
        <h5>{name}</h5>
        <p>{text}</p>
      </div>
    </div>
  );
};

And this is the characters.js object:

export const characters = {
  design: {
    name: "MAGNIFICENT DESIGN DOCTOR",
    text: "Through visual seduction you can morph new realities to existance. You blend your weapons of UI/UX in your test laboraty into a paralizing elixir. Your allies are the fearless frontend ninjas.",
    image: require("../public/assets/Design Doctor.svg"),
  },
  front: {
    name: "FEARLESS FRONTEND NINJA",
    text: "With sharp-sighted intuition for aesthetics, your area of operations is the front line. With concept and design, you walk into battle to defeat your worst enemy: The Internet Explorer.",
    image: require("../public/assets/Ninja.svg"),
  },
  back: {
    name: "BASHING BACKEND BEAR",
    text: "With keyboard and terminal you hack bugs up as if there was no tomorrow. The mouse is used only during emergencies and you save the day when the frontend needs heavy weapons.",
    image: require("../public/assets/Bashing Bear.svg"),
  },
  engineer: {
    name: "SUPERIOR SERVER/OS ENGINEER",
    text: "You are the specialist for heavy, server-driven weapons. Your deployment pipeline is the backbone of any operation. Precisely automated actions are executed through your scripts to prevent any hostile infiltration.",
    image: require("../public/assets/Hulk.svg"),
  },
};

Answer

I think this could be because your characters object is has not been typed. I would suggest you change it from a .js file to a .ts file, and give it a type. For example you could do something like this for characters.ts.

type Character = {
    name: string,
    text: string,
    image: typeof import("*.svg")
};

type CharacterSet = { design: Character, front: Character, back: Character, engineer: Character };

export const characters: CharacterSet = {

  design: {
    name: "MAGNIFICENT DESIGN DOCTOR",
    text: "Through visual seduction you can morph new realities to existance. You blend your weapons of UI/UX in your test laboraty into a paralizing elixir. Your allies are the fearless frontend ninjas.",
    image: require("../public/assets/Design Doctor.svg"),
  },
  front: {
    name: "FEARLESS FRONTEND NINJA",
    text: "With sharp-sighted intuition for aesthetics, your area of operations is the front line. With concept and design, you walk into battle to defeat your worst enemy: The Internet Explorer.",
    image: require("../public/assets/Ninja.svg"),
  },
  back: {
    name: "BASHING BACKEND BEAR",
    text: "With keyboard and terminal you hack bugs up as if there was no tomorrow. The mouse is used only during emergencies and you save the day when the frontend needs heavy weapons.",
    image: require("../public/assets/Bashing Bear.svg"),
  },
  engineer: {
    name: "SUPERIOR SERVER/OS ENGINEER",
    text: "You are the specialist for heavy, server-driven weapons. Your deployment pipeline is the backbone of any operation. Precisely automated actions are executed through your scripts to prevent any hostile infiltration.",
    image: require("../public/assets/Hulk.svg"),
  },
}