react-select icon indicating copy to clipboard operation
react-select copied to clipboard

Runtime error if options are array of strings

Open alamothe opened this issue 3 years ago • 6 comments

If options are array of strings:

			<Select
				options={["a", "b", "c"]}
				value={value}
				getOptionValue={e => e}
				getOptionLabel={e => e}
				onChange={e => setValue(e)}
			/>

There is a runtime error:

Uncaught TypeError: Cannot use 'in' operator to search for 'options' in 1

Which happens here: https://github.com/JedWatson/react-select/blob/master/packages/react-select/src/Select.tsx#L382

Sometimes it is really convenient if options is an array of predefined strings (enum).

It could be fixed just by doing a typeof guard.

alamothe avatar Oct 08 '22 10:10 alamothe

I ran into this problem as well, with an enum. What was your workaround?

JonnyHaystack avatar Jan 14 '23 00:01 JonnyHaystack

Most compact workaround I could think of is to use String object. Being an object, it's compatible with in operator.

Since String object and string primitive are both coerce to the same string value, only options has to be wrapped with objects.

<Select
  options={["a", "b", "c"].map(it => new String(it))}
  value={value}
  getOptionValue={String}
  getOptionLabel={String}
  onChange={e => setValue(String(e))}
/>

See more about String() constructor and about primitive wrapper types caveats.

fen-x avatar Jan 17 '23 13:01 fen-x

Which happens here: https://github.com/JedWatson/react-select/blob/master/packages/react-select/src/Select.tsx#L382

BTW, due to some changes the line has moved since then. Now (v5.7.0) it is L397.

fen-x avatar Jan 17 '23 13:01 fen-x

The String workaround doesn't work for me if it's not a isMutli. I wasn't able to make it work with single select

alamothe avatar Jul 21 '23 01:07 alamothe

Typescript complains about the new String() wrapper workaround. This is the only way I could make it work:

options={ [{ options: ["a", "b", "c"] }] }

which fakes a GroupBase type. The downside is that there's a small extra margin at the start of the dropdown but it can be fixed with CSS.

juhana avatar Sep 24 '23 18:09 juhana

Another option is to map all the strings into a wrapper object like

options.map(o => ({ value: o })

however you have to then also map value properly:

value={options.find(o => o.value === value)}

it would be much nicer if using string values worked directly, especially when migrating existing <select> usages (which only work with string values) to react-select.

felixfbecker avatar Apr 01 '24 21:04 felixfbecker