Skip to content

Commit

Permalink
[useAutocomplete] Improve TS typing of groupedOptions prop (#44657)
Browse files Browse the repository at this point in the history
Co-authored-by: Zeeshan Tamboli <zeeshan.tamboli@gmail.com>
  • Loading branch information
lewxdev and ZeeshanTamboli authored Dec 18, 2024
1 parent 7f04342 commit 1920b80
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { useAutocomplete } from '@mui/base/useAutocomplete';
import useAutocomplete from '@mui/material/useAutocomplete';
import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close';
import { styled } from '@mui/material/styles';
Expand Down
6 changes: 4 additions & 2 deletions docs/data/material/components/autocomplete/CustomizedHook.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as React from 'react';
import { useAutocomplete, AutocompleteGetTagProps } from '@mui/base/useAutocomplete';
import useAutocomplete, {
AutocompleteGetTagProps,
} from '@mui/material/useAutocomplete';
import CheckIcon from '@mui/icons-material/Check';
import CloseIcon from '@mui/icons-material/Close';
import { styled } from '@mui/material/styles';
Expand Down Expand Up @@ -188,7 +190,7 @@ export default function CustomizedHook() {
</div>
{groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}>
{(groupedOptions as typeof top100Films).map((option, index) => {
{groupedOptions.map((option, index) => {
const { key, ...optionProps } = getOptionProps({ option, index });
return (
<li key={key} {...optionProps}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { useAutocomplete } from '@mui/base/useAutocomplete';
import useAutocomplete from '@mui/material/useAutocomplete';
import { styled } from '@mui/system';

const Label = styled('label')({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import { useAutocomplete } from '@mui/base/useAutocomplete';
import useAutocomplete from '@mui/material/useAutocomplete';
import { styled } from '@mui/system';

const Label = styled('label')({
Expand Down Expand Up @@ -63,7 +63,7 @@ export default function UseAutocomplete() {
</div>
{groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}>
{(groupedOptions as typeof top100Films).map((option, index) => {
{groupedOptions.map((option, index) => {
const { key, ...optionProps } = getOptionProps({ option, index });
return (
<li key={key} {...optionProps}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
</div>
{groupedOptions.length > 0 ? (
<Listbox {...getListboxProps()}>
{(groupedOptions as typeof top100Films).map((option, index) => {
{groupedOptions.map((option, index) => {
const { key, ...optionProps } = getOptionProps({ option, index });
return (
<li key={key} {...optionProps}>
Expand Down
2 changes: 1 addition & 1 deletion docs/pages/material-ui/api/autocomplete.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
},
"groupBy": {
"type": { "name": "func" },
"signature": { "type": "function(options: Value) => string", "describedArgs": ["options"] }
"signature": { "type": "function(option: Value) => string", "describedArgs": ["option"] }
},
"handleHomeEndKeys": { "type": { "name": "bool" }, "default": "!props.freeSolo" },
"id": { "type": { "name": "string" } },
Expand Down
2 changes: 1 addition & 1 deletion docs/translations/api-docs/autocomplete/autocomplete.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
},
"groupBy": {
"description": "If provided, the options will be grouped under the returned string. The groupBy value is also used as the text for group headings when <code>renderGroup</code> is not provided.",
"typeDescriptions": { "options": "The options to group." }
"typeDescriptions": { "option": "The Autocomplete option." }
},
"handleHomeEndKeys": {
"description": "If <code>true</code>, the component handles the &quot;Home&quot; and &quot;End&quot; keys when the popup is open. It should move focus to the first option and last option, respectively."
Expand Down
2 changes: 1 addition & 1 deletion packages/mui-material/src/Autocomplete/Autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -994,7 +994,7 @@ Autocomplete.propTypes /* remove-proptypes */ = {
* If provided, the options will be grouped under the returned string.
* The groupBy value is also used as the text for group headings when `renderGroup` is not provided.
*
* @param {Value} options The options to group.
* @param {Value} option The Autocomplete option.
* @returns {string}
*/
groupBy: PropTypes.func,
Expand Down
25 changes: 20 additions & 5 deletions packages/mui-material/src/useAutocomplete/useAutocomplete.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { PartiallyRequired } from '@mui/types';

export interface CreateFilterOptionsConfig<Value> {
ignoreAccents?: boolean;
Expand Down Expand Up @@ -178,7 +179,7 @@ export interface UseAutocompleteProps<
* If provided, the options will be grouped under the returned string.
* The groupBy value is also used as the text for group headings when `renderGroup` is not provided.
*
* @param {Value} options The options to group.
* @param {Value} option The Autocomplete option.
* @returns {string}
*/
groupBy?: (option: Value) => string;
Expand Down Expand Up @@ -359,8 +360,19 @@ export function useAutocomplete<
DisableClearable extends boolean | undefined = false,
FreeSolo extends boolean | undefined = false,
>(
props: UseAutocompleteProps<Value, Multiple, DisableClearable, FreeSolo>,
): UseAutocompleteReturnValue<Value, Multiple, DisableClearable, FreeSolo>;
props: PartiallyRequired<
UseAutocompleteProps<Value, Multiple, DisableClearable, FreeSolo>,
'groupBy'
>,
): UseAutocompleteReturnValue<Value, Multiple, DisableClearable, FreeSolo, true>;
export function useAutocomplete<
Value,
Multiple extends boolean | undefined = false,
DisableClearable extends boolean | undefined = false,
FreeSolo extends boolean | undefined = false,
>(
props: Omit<UseAutocompleteProps<Value, Multiple, DisableClearable, FreeSolo>, 'groupBy'>,
): UseAutocompleteReturnValue<Value, Multiple, DisableClearable, FreeSolo, false>;

export interface UseAutocompleteRenderedOption<Value> {
option: Value;
Expand All @@ -372,6 +384,7 @@ export interface UseAutocompleteReturnValue<
Multiple extends boolean | undefined = false,
DisableClearable extends boolean | undefined = false,
FreeSolo extends boolean | undefined = false,
HasGroupBy extends boolean = false,
> {
/**
* Resolver for the root slot's props.
Expand Down Expand Up @@ -460,9 +473,11 @@ export interface UseAutocompleteReturnValue<
*/
focusedTag: number;
/**
* The options to render. It's either `Value[]` or `AutocompleteGroupedOption<Value>[]` if the groupBy prop is provided.
* The options to render.
* - If `groupBy` is provided, the options are grouped and represented as `AutocompleteGroupedOption<Value>[]`.
* - Otherwise, the options are represented as a flat array of `Value[]`.
*/
groupedOptions: Value[] | Array<AutocompleteGroupedOption<Value>>;
groupedOptions: HasGroupBy extends true ? AutocompleteGroupedOption<Value>[] : Value[];
}

export default useAutocomplete;
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { expectType } from '@mui/types';
import { useAutocomplete, FilterOptionsState } from '@mui/material/useAutocomplete';
import {
useAutocomplete,
FilterOptionsState,
AutocompleteGroupedOption,
} from '@mui/material/useAutocomplete';

interface Person {
id: string;
Expand Down Expand Up @@ -181,4 +185,17 @@ function Component() {
},
freeSolo: true,
});

const ungroupedAutocomplete = useAutocomplete({ options: persons });
expectType<Person[], typeof ungroupedAutocomplete.groupedOptions>(
ungroupedAutocomplete.groupedOptions,
);

const groupedAutocomplete = useAutocomplete({
options: persons,
groupBy: ({ id }) => id,
});
expectType<AutocompleteGroupedOption<Person>[], typeof groupedAutocomplete.groupedOptions>(
groupedAutocomplete.groupedOptions,
);
}

0 comments on commit 1920b80

Please sign in to comment.