Your question has been updated to specify that the multi
property should be optional, with a default value of false. This eliminates the possibility of using a discriminated union as outlined in the previous answer below.
In this case, I would recommend using two interfaces that can be combined into a union, along with a base interface for shared properties. Type guard functions will also come in handy when determining the type of the select.
// Common properties for all MySelects (other than `onChange`)
interface MySelectBase {
name: string;
}
// Interface for single-select MySelect
interface MySingleSelect extends MySelectBase {
multi?: false;
onChange: (item: string) => void;
}
// Interface for multi-select MySelect
interface MyMultiSelect extends MySelectBase {
multi: true;
onChange: (items: string[]) => void;
}
// Unified type combining both single and multi selects
type MySelect = MySingleSelect | MyMultiSelect;
// Type guard function to check if it's a single select
const isSingleSelect = (select: MySelect): select is MySingleSelect => {
return !select.multi; // Returns true for !undefined and !false
};
// Type guard function to check if it's a multi select
const isMultiSelect = (select: MySelect): select is MyMultiSelect => {
return !!select.multi; // Returns true for !!undefined and !!true
};
Examples of creating instances:
const single: MySingleSelect = {
name: "some-single-select-field",
onChange : (item) => { console.log(item); }
};
const multi: MyMultiSelect = {
multi: true,
name: "some-multi-select-field",
onChange : (items) => { console.log(items); }
};
Example of utilizing the MySelect
interface:
const useMySelect = (select: MySelect) => {
console.log(select.name);
const onChange = select.onChange;
if (isSingleSelect(select)) {
const onChange = select.onChange;
} else {
const onChange = select.onChange;
}
};
This original answer caters to scenarios where making the multi
property optional is not a requirement:
You can achieve this by defining MySelect
as a union of types based on the value of multi
, either true or false:
type MySelect =
{
multi: true;
onChange: (items: string[]) => void;
}
|
{
multi: false;
onChange: (item: string) => void;
};
For example:
const mySelect: MySelect = {
multi: true,
onChange: (items) => {}
};
This is referred to as a discriminated union, where the union is distinguished by a particular field value.
If there are additional common properties apart from 'multi' and 'onChange', you can include them in the discriminated union using intersections:
type MySelect =
(
{
multi: true;
onChange: (items: string[]) => void;
}
|
{
multi: false;
onChange: (item: string) => void;
}
)
&
{
the: number;
other: string;
properties: string;
};