John Lenehan
John Lenehan

Reputation: 45

Generic React Component Interface whose property types can change based on specific property

Is there a way to create a React Component with Typescript where certain properties change their types based on the existence/type of a different property?

I am attempting to build a generic react select component, that can either be a multi select or a single select. It will have a renderValues property that will be used to render the selected values. Ideally, if this component is a multi select, renderValues would have the signature:

(selected: T[]) => JSX.Element

and if it's a single select it would have the signature

(selected: T) => JSX.Element

An example of a multi select component would be:

<SingleOrMultiSelect
  multiple={true}
  value={['foo','bar']}
  options={['foo','bar','biz','baz']}
  renderValues={(opts: string[])=> opts.join(', ')}
  name={'Example Multi Select'
/>

Here is a Typescript playground showing what I've started trying

It's based heavily off of the OverideableComponent from Material UI but I can't seem to get this working.

Realistically I will just split this logic into a SingleSelect component and a multiselect component, or more likely just require renderValues to always expect an array, but I am now curious if there is a clean way to achieve what I had originally sought to do.

Additional Playground link with the below answer implemented

Upvotes: 1

Views: 184

Answers (1)

Gianfranco Fertino
Gianfranco Fertino

Reputation: 632

You can do something like this

interface SingleSelectProps {
  multiple: true;
  renderValues: (opts: string[]) => React.ReactNode
}

interface MultiSelectProps {
  multiple: false;
  renderValues: (opts: string) => React.ReactNode
}

type SingleOrMultiSelectProps = SingleSelectProps | MultiSelectProps;

Upvotes: 1

Related Questions