skip to Main Content

I am getting select-box options, iterate labels, optgroup & values into select-box. Is there anything wrong with the way I have created my types?

interface Option {
  label: string
  value: string
  selected?:boolean
  mainGroup?: string
  optgroup?: "" | string | [] | undefined
}

const trackNames: Option[] = [
  {
    value: "Track1",
    label: "Track One",
    optgroup: "",
  },
  {
    value: "Track2",
    label: "Track Two",
    optgroup: "",
  },
  {
    value: "Track3",
    label: "Track Three",
    optgroup: "Track3-Group",
  },
  {
    value: "Track4",
    label: "Track Four",
    optgroup: "Track3-Group",
  }
];

// sample.js code

import { trackNames as trackNameData } from '/helper/Data'

const groupedOptions = {};
  
trackNameData.forEach((option: { optgroup: any; value: any; label: any }) => {
    
  if (!groupedOptions[option.optgroup]) groupedOptions[option.optgroup] = [];
    groupedOptions[option.optgroup].push({
      value: option.value,
      label: option.label,
  });

});

const renderOptions = (options: any[]) => {
   return options.map((option) => {
     return (
       <option key={option.value} value={option.value}>
         {option.label}
       </option>
       );
    });
};

<select>   
    <option value=''>Please select</option>
    {Object.keys(groupedOptions).map((group, index) => {
    return (
      <optgroup key={index} label={group}>
      {renderOptions(groupedOptions[group])}
    </optgroup>
    );
    })}
</select>

When I am importing trackData into another JS file to show otions in Select-box gave me below error:

Element implicitly has an 'any' type because expression of type 'any' can't be used to index type '{}'.ts(7053)

What am I doing wrong? I’ve looked at other solutions and can’t get it to work.

2

Answers


  1. If you’re going to be indexing into groupedOptions with some arbitrary key, then you want to give it a type with an index signature. From your code example as given I’d expect you want the values to be arrays of Options. So the type {[k: string]: Option[]} or the equivalent Record<string, Option[]> (using the Record utility type) would work:

    const groupedOptions: Record<string, Option[]> = {};
    

    Once you do that, it will not be an error to write groupedOptions[xxx] as long as xxx is keylike:

    trackNames.forEach((option: { optgroup?: any; value: any; label: any }) => {
      if (!groupedOptions[option.optgroup]) groupedOptions[option.optgroup] = [];
      groupedOptions[option.optgroup].push({
        value: option.value,
        label: option.label,
      });
    });
    

    That now compiles as written without error. But do note that you have given optgroup the intentionally loose any type which mostly turns off type checking. Generally speaking you should only be indexing into objects with strings, numbers, or symbols. If optgroup can really be undefined or an empty array [] (note that [] is a tuple type of zero elements and not an arbitrary array type), then indexing into an object with it will have surprising results. I’m considering this out of scope for the question as asked, but you should really make sure that your object keys are valid.

    Playground link to code

    Login or Signup to reply.
  2. interface Option {
      label: string
      value: string
      selected?:boolean
      mainGroup?: string
      optgroup?: "" | string | [] | undefined
    }
    
    const trackNames = [
      {
        value: "Track1",
        label: "Track One",
        optgroup: "",
      },
      {
        value: "Track2",
        label: "Track Two",
        optgroup: "",
      },
      {
        value: "Track3",
        label: "Track Three",
        optgroup: "Track3-Group",
      },
      {
        value: "Track4",
        label: "Track Four",
        optgroup: "Track3-Group",
      }
    ] as const satisfies Option[];
    
    const groupedOptions: { [key in typeof trackNames[number]['optgroup']]: { value: string, label: string }[] } = {} as any;
      
    trackNames.forEach((option) => {
      if (!groupedOptions[option.optgroup]) groupedOptions[option.optgroup] = [];
      groupedOptions[option.optgroup].push({
        value: option.value,
        label: option.label,
      });
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search