mirror of
https://github.com/gosticks/DefinitelyTyped.git
synced 2026-10-04 14:57:10 +00:00
Merge pull request #19538 from begincalendar/fix-19515
[react-select] Fix #19515 to create consistent generic usage of Option and Options types
This commit is contained in:
Vendored
+43
-43
@@ -17,20 +17,20 @@ export = ReactSelectClass;
|
||||
|
||||
declare namespace ReactSelectClass {
|
||||
// Other components
|
||||
class Creatable extends React.Component<ReactCreatableSelectProps> { }
|
||||
class Async extends React.Component<ReactAsyncSelectProps> { }
|
||||
class AsyncCreatable extends React.Component<ReactAsyncSelectProps & ReactCreatableSelectProps> { }
|
||||
class Creatable<TValue = OptionValues> extends React.Component<ReactCreatableSelectProps<TValue>> { }
|
||||
class Async<TValue = OptionValues> extends React.Component<ReactAsyncSelectProps<TValue>> { }
|
||||
class AsyncCreatable<TValue = OptionValues> extends React.Component<ReactAsyncSelectProps<TValue> & ReactCreatableSelectProps<TValue>> { }
|
||||
|
||||
type HandlerRendererResult = JSX.Element | null | false;
|
||||
|
||||
// Handlers
|
||||
type FocusOptionHandler = (option: Option) => void;
|
||||
type SelectValueHandler = (option: Option) => void;
|
||||
type FocusOptionHandler<TValue = OptionValues> = (option: Option<TValue>) => void;
|
||||
type SelectValueHandler<TValue = OptionValues> = (option: Option<TValue>) => void;
|
||||
type ArrowRendererHandler = (props: ArrowRendererProps) => HandlerRendererResult;
|
||||
type FilterOptionHandler = (option: Option, filter: string) => Option;
|
||||
type FilterOptionsHandler = (options: Options, filter: string, currentValues: Options) => Options;
|
||||
type FilterOptionHandler<TValue = OptionValues> = (option: Option<TValue>, filter: string) => Option<TValue>;
|
||||
type FilterOptionsHandler<TValue = OptionValues> = (options: Options<TValue>, filter: string, currentValues: Options<TValue>) => Options<TValue>;
|
||||
type InputRendererHandler = (props: { [key: string]: any }) => HandlerRendererResult;
|
||||
type MenuRendererHandler = (props: MenuRendererProps) => HandlerRendererResult;
|
||||
type MenuRendererHandler<TValue = OptionValues> = (props: MenuRendererProps<TValue>) => HandlerRendererResult;
|
||||
type OnCloseHandler = () => void;
|
||||
type OnInputChangeHandler = (inputValue: string) => void;
|
||||
type OnInputKeyDownHandler = React.KeyboardEventHandler<HTMLDivElement | HTMLInputElement>;
|
||||
@@ -38,27 +38,27 @@ declare namespace ReactSelectClass {
|
||||
type OnOpenHandler = () => void;
|
||||
type OnFocusHandler = React.FocusEventHandler<HTMLDivElement | HTMLInputElement>;
|
||||
type OnBlurHandler = React.FocusEventHandler<HTMLDivElement | HTMLInputElement>;
|
||||
type OptionRendererHandler = (option: Option) => HandlerRendererResult;
|
||||
type ValueRendererHandler = (option: Option) => HandlerRendererResult;
|
||||
type OptionRendererHandler<TValue = OptionValues> = (option: Option<TValue>) => HandlerRendererResult;
|
||||
type ValueRendererHandler<TValue = OptionValues> = (option: Option<TValue>) => HandlerRendererResult;
|
||||
type OnValueClickHandler = (value: string, event: React.MouseEvent<HTMLAnchorElement>) => void;
|
||||
type IsOptionUniqueHandler = (arg: { option: Option, options: Options, labelKey: string, valueKey: string }) => boolean;
|
||||
type IsOptionUniqueHandler<TValue = OptionValues> = (arg: { option: Option<TValue>, options: Options<TValue>, labelKey: string, valueKey: string }) => boolean;
|
||||
type IsValidNewOptionHandler = (arg: { label: string }) => boolean;
|
||||
type NewOptionCreatorHandler = (arg: { label: string, labelKey: string, valueKey: string }) => Option;
|
||||
type NewOptionCreatorHandler<TValue = OptionValues> = (arg: { label: string, labelKey: string, valueKey: string }) => Option<TValue>;
|
||||
type PromptTextCreatorHandler = (filterText: string) => string;
|
||||
type ShouldKeyDownEventCreateNewOptionHandler = (arg: { keyCode: number }) => boolean;
|
||||
|
||||
type OnChangeSingleHandler<TValue = OptionValues> = OnChangeHandler<Option<TValue>>;
|
||||
type OnChangeMultipleHandler<TValue = OptionValues> = OnChangeHandler<Options<TValue>>;
|
||||
type OnChangeHandler<TOption = Option | Options> = (newValue: TOption | null) => void;
|
||||
type OnNewOptionClickHandler = (option: Option) => void;
|
||||
type OnChangeSingleHandler<TValue = OptionValues> = OnChangeHandler<TValue, Option<TValue>>;
|
||||
type OnChangeMultipleHandler<TValue = OptionValues> = OnChangeHandler<TValue, Options<TValue>>;
|
||||
type OnChangeHandler<TValue = OptionValues, TOption = Option<TValue> | Options<TValue>> = (newValue: TOption | null) => void;
|
||||
type OnNewOptionClickHandler<TValue = OptionValues> = (option: Option<TValue>) => void;
|
||||
|
||||
type LoadOptionsHandler = LoadOptionsAsyncHandler | LoadOptionsLegacyHandler;
|
||||
type LoadOptionsAsyncHandler = (input: string) => Promise<AutocompleteResult>;
|
||||
type LoadOptionsLegacyHandler = (input: string, callback: (err: any, result: AutocompleteResult) => void) => void;
|
||||
type LoadOptionsHandler<TValue = OptionValues> = LoadOptionsAsyncHandler<TValue> | LoadOptionsLegacyHandler<TValue>;
|
||||
type LoadOptionsAsyncHandler<TValue = OptionValues> = (input: string) => Promise<AutocompleteResult<TValue>>;
|
||||
type LoadOptionsLegacyHandler<TValue = OptionValues> = (input: string, callback: (err: any, result: AutocompleteResult<TValue>) => void) => void;
|
||||
|
||||
interface AutocompleteResult {
|
||||
interface AutocompleteResult<TValue = OptionValues> {
|
||||
/** The search-results to be displayed */
|
||||
options: Options;
|
||||
options: Options<TValue>;
|
||||
/**
|
||||
* Should be set to true, if and only if a longer query with the same prefix
|
||||
* would return a subset of the results
|
||||
@@ -93,17 +93,17 @@ declare namespace ReactSelectClass {
|
||||
|
||||
type OptionValues = string | number | boolean;
|
||||
|
||||
interface MenuRendererProps {
|
||||
interface MenuRendererProps<TValue = OptionValues> {
|
||||
/**
|
||||
* The currently focused option; should be visible in the menu by default.
|
||||
* default {}
|
||||
*/
|
||||
focusedOption: Option;
|
||||
focusedOption: Option<TValue>;
|
||||
|
||||
/**
|
||||
* Callback to focus a new option; receives the option as a parameter.
|
||||
*/
|
||||
focusOption: FocusOptionHandler;
|
||||
focusOption: FocusOptionHandler<TValue>;
|
||||
|
||||
/**
|
||||
* Option labels are accessible with this string key.
|
||||
@@ -113,17 +113,17 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* Ordered array of options to render.
|
||||
*/
|
||||
options: Options;
|
||||
options: Options<TValue>;
|
||||
|
||||
/**
|
||||
* Callback to select a new option; receives the option as a parameter.
|
||||
*/
|
||||
selectValue: SelectValueHandler;
|
||||
selectValue: SelectValueHandler<TValue>;
|
||||
|
||||
/**
|
||||
* Array of currently selected options.
|
||||
*/
|
||||
valueArray: Options;
|
||||
valueArray: Options<TValue>;
|
||||
}
|
||||
|
||||
interface ArrowRendererProps {
|
||||
@@ -133,7 +133,7 @@ declare namespace ReactSelectClass {
|
||||
onMouseDown: React.MouseEventHandler<any>;
|
||||
}
|
||||
|
||||
interface ReactSelectProps extends React.Props<ReactSelectClass> {
|
||||
interface ReactSelectProps<TValue = OptionValues> extends React.Props<ReactSelectClass<TValue>> {
|
||||
/**
|
||||
* text to display when `allowCreate` is true.
|
||||
* @default 'Add "{label}"?'
|
||||
@@ -206,11 +206,11 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* method to filter a single option
|
||||
*/
|
||||
filterOption?: FilterOptionHandler;
|
||||
filterOption?: FilterOptionHandler<TValue>;
|
||||
/**
|
||||
* method to filter the options array
|
||||
*/
|
||||
filterOptions?: FilterOptionsHandler;
|
||||
filterOptions?: FilterOptionsHandler<TValue>;
|
||||
/**
|
||||
* whether to strip diacritics when filtering
|
||||
* @default true
|
||||
@@ -273,7 +273,7 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* renders a custom menu with options
|
||||
*/
|
||||
menuRenderer?: MenuRendererHandler;
|
||||
menuRenderer?: MenuRendererHandler<TValue>;
|
||||
/**
|
||||
* optional style to apply to the menu
|
||||
*/
|
||||
@@ -304,7 +304,7 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* onChange handler: function (newValue) {}
|
||||
*/
|
||||
onChange?: OnChangeHandler;
|
||||
onChange?: OnChangeHandler<TValue>;
|
||||
/**
|
||||
* fires when the menu is closed
|
||||
*/
|
||||
@@ -350,12 +350,12 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* function which returns a custom way to render the options in the menu
|
||||
*/
|
||||
optionRenderer?: OptionRendererHandler;
|
||||
optionRenderer?: OptionRendererHandler<TValue>;
|
||||
/**
|
||||
* array of Select options
|
||||
* @default false
|
||||
*/
|
||||
options?: Options;
|
||||
options?: Options<TValue>;
|
||||
/**
|
||||
* field placeholder, displayed when there's no value
|
||||
* @default "Select..."
|
||||
@@ -387,7 +387,7 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* initial field value
|
||||
*/
|
||||
value?: Option | Options | string | string[] | number | number[] | boolean;
|
||||
value?: Option<TValue> | Options<TValue> | string | string[] | number | number[] | boolean;
|
||||
/**
|
||||
* the option property to use for the value
|
||||
* @default "value"
|
||||
@@ -397,7 +397,7 @@ declare namespace ReactSelectClass {
|
||||
* function which returns a custom way to render the value selected
|
||||
* @default false
|
||||
*/
|
||||
valueRenderer?: ValueRendererHandler;
|
||||
valueRenderer?: ValueRendererHandler<TValue>;
|
||||
/**
|
||||
* optional style to apply to the control
|
||||
*/
|
||||
@@ -429,12 +429,12 @@ declare namespace ReactSelectClass {
|
||||
simpleValue?: boolean;
|
||||
}
|
||||
|
||||
interface ReactCreatableSelectProps extends ReactSelectProps {
|
||||
interface ReactCreatableSelectProps<TValue = OptionValues> extends ReactSelectProps<TValue> {
|
||||
/**
|
||||
* Searches for any matching option within the set of options. This function prevents
|
||||
* duplicate options from being created.
|
||||
*/
|
||||
isOptionUnique?: IsOptionUniqueHandler;
|
||||
isOptionUnique?: IsOptionUniqueHandler<TValue>;
|
||||
|
||||
/**
|
||||
* Determines if the current input text represents a valid option.
|
||||
@@ -444,7 +444,7 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* factory to create new options
|
||||
*/
|
||||
newOptionCreator?: NewOptionCreatorHandler;
|
||||
newOptionCreator?: NewOptionCreatorHandler<TValue>;
|
||||
|
||||
/**
|
||||
* Creates prompt/placeholder for option text.
|
||||
@@ -459,10 +459,10 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* new option click handler: function (option) {}
|
||||
*/
|
||||
onNewOptionClick?: OnNewOptionClickHandler;
|
||||
onNewOptionClick?: OnNewOptionClickHandler<TValue>;
|
||||
}
|
||||
|
||||
interface ReactAsyncSelectProps extends ReactSelectProps {
|
||||
interface ReactAsyncSelectProps<TValue = OptionValues> extends ReactSelectProps<TValue> {
|
||||
/**
|
||||
* Whether to auto-load the default async options set.
|
||||
*/
|
||||
@@ -491,7 +491,7 @@ declare namespace ReactSelectClass {
|
||||
/**
|
||||
* function to call to load options asynchronously
|
||||
*/
|
||||
loadOptions: LoadOptionsHandler;
|
||||
loadOptions: LoadOptionsHandler<TValue>;
|
||||
|
||||
/**
|
||||
* replaces the placeholder while options are loading
|
||||
@@ -524,6 +524,6 @@ declare namespace ReactSelectClass {
|
||||
}
|
||||
}
|
||||
|
||||
declare class ReactSelectClass extends React.Component<ReactSelectClass.ReactSelectProps> {
|
||||
declare class ReactSelectClass<TValue = ReactSelectClass.OptionValues> extends React.Component<ReactSelectClass.ReactSelectProps<TValue>> {
|
||||
focus(): void;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,29 @@ const EXAMPLE_OPTIONS: ReactSelect.Options = [
|
||||
{ value: "two", label: "Two" }
|
||||
];
|
||||
|
||||
interface CustomValueType {
|
||||
prop1: string;
|
||||
prop2: number;
|
||||
}
|
||||
|
||||
/*
|
||||
* This JSX/TSX generic component workaround is needed because of this issue:
|
||||
* https://github.com/Microsoft/TypeScript/issues/3960
|
||||
* If https://github.com/Microsoft/TypeScript/issues/6395 ever lands, this
|
||||
* workaround may become redundant.
|
||||
*/
|
||||
type CustomValueReactSelect = new (props: ReactSelect.ReactSelectProps<CustomValueType>) => ReactSelect<CustomValueType>;
|
||||
const CustomValueReactSelect = ReactSelect as CustomValueReactSelect;
|
||||
|
||||
const EXAMPLE_CUSTOM_OPTIONS: ReactSelect.Options<CustomValueType> = [
|
||||
{ value: { prop1: "OneProp1", prop2: 1 }, label: "One" },
|
||||
{ value: { prop1: "TwoProp2", prop2: 2 }, label: "Two" }
|
||||
];
|
||||
|
||||
const EXAMPLE_CUSTOM_VALUE: ReactSelect.Option<CustomValueType> = {
|
||||
value: { prop1: "ThreeProp1", prop2: 3 }, label: "Three"
|
||||
};
|
||||
|
||||
describe("react-select", () => {
|
||||
it("options", () => {
|
||||
const optionsString: ReactSelect.Options<string> = [
|
||||
@@ -56,6 +79,34 @@ describe("react-select", () => {
|
||||
};
|
||||
});
|
||||
|
||||
it("Custom value async options", () => {
|
||||
const getAsyncLegacyOptions: ReactSelect.LoadOptionsLegacyHandler<CustomValueType> = (input, callback) => {
|
||||
setTimeout(() => {
|
||||
callback(null, {
|
||||
options: [
|
||||
{ value: { prop1: "One", prop2: 4 }, label: "Two" }
|
||||
],
|
||||
complete: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const dummyRequest = async () => {
|
||||
return new Promise<ReactSelect.Options<CustomValueType>>(resolve => {
|
||||
resolve(EXAMPLE_CUSTOM_OPTIONS);
|
||||
});
|
||||
};
|
||||
|
||||
const getAsyncOptions: ReactSelect.LoadOptionsAsyncHandler<CustomValueType> = async input => {
|
||||
const result = await dummyRequest();
|
||||
|
||||
return {
|
||||
options: result,
|
||||
complete: false
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
it("creatable", () => {
|
||||
function Component(props: {}): JSX.Element {
|
||||
return <Creatable name="creatable" options={EXAMPLE_OPTIONS} />;
|
||||
@@ -135,6 +186,22 @@ describe("Examples", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("Custom value onChange", () => {
|
||||
class Component extends React.Component {
|
||||
private onSelectChange: ReactSelect.OnChangeSingleHandler<CustomValueType> = (option) => {
|
||||
const optionValue: CustomValueType = option.value;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <CustomValueReactSelect
|
||||
name="select"
|
||||
value={EXAMPLE_CUSTOM_VALUE}
|
||||
options={EXAMPLE_CUSTOM_OPTIONS}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("Menu renderer example", () => {
|
||||
class Component extends React.Component {
|
||||
private onSelectChange: ReactSelect.OnChangeSingleHandler<string> = option => {
|
||||
@@ -160,6 +227,32 @@ describe("Examples", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("Menu renderer with custom value type example", () => {
|
||||
class Component extends React.Component {
|
||||
private menuRenderer: ReactSelect.MenuRendererHandler<CustomValueType> = props => {
|
||||
const options = props.options.map(option => {
|
||||
return (
|
||||
<div className="option" data-value1={option.value.prop1}
|
||||
data-value2={option.value.prop2}
|
||||
onClick={() => props.selectValue(option)}>
|
||||
{option.label}
|
||||
</div>);
|
||||
});
|
||||
|
||||
return <div className="menu">{options}</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
return <CustomValueReactSelect
|
||||
name="select"
|
||||
value={EXAMPLE_CUSTOM_VALUE}
|
||||
options={EXAMPLE_CUSTOM_OPTIONS}
|
||||
menuRenderer={this.menuRenderer}
|
||||
/>;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("Input render example", () => {
|
||||
class Component extends React.Component {
|
||||
private onSelectChange: ReactSelect.OnChangeSingleHandler<string> = option => {
|
||||
@@ -201,6 +294,24 @@ describe("Examples", () => {
|
||||
/>;
|
||||
});
|
||||
|
||||
it("Option render with custom value option", () => {
|
||||
const optionRenderer = (option: ReactSelect.Option<CustomValueType>): ReactSelect.HandlerRendererResult =>
|
||||
null;
|
||||
|
||||
<CustomValueReactSelect
|
||||
optionRenderer={optionRenderer}
|
||||
/>;
|
||||
});
|
||||
|
||||
it("Value render with custom value option", () => {
|
||||
const valueRenderer = (option: ReactSelect.Option<CustomValueType>): ReactSelect.HandlerRendererResult =>
|
||||
null;
|
||||
|
||||
<CustomValueReactSelect
|
||||
valueRenderer={valueRenderer}
|
||||
/>;
|
||||
});
|
||||
|
||||
it("No Results renderer with string", () => {
|
||||
<ReactSelect noResultsText="no results" />;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user