Skip to content

Commit

Permalink
CustomSelectControl: improve props type inferring (#64412)
Browse files Browse the repository at this point in the history
* CustomSelectControl: improve props type inferring

* chore: update changelog

* chore: updates

Co-authored-by: meteorlxy <[email protected]>
Co-authored-by: mirka <[email protected]>
  • Loading branch information
3 people authored Aug 16, 2024
1 parent 68dd5ce commit 8169dfd
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 3 deletions.
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@
- `Composite` v2: add focus-related props to `Composite`and`Composite.Item` subcomponents ([#64450](https://github.com/WordPress/gutenberg/pull/64450)).
- `Composite` v2: add `Context` subcomponent ([#64493](https://github.com/WordPress/gutenberg/pull/64493)).

### Internal

- `CustomSelectControl`: Improve type inferring ([#64412](https://github.com/WordPress/gutenberg/pull/64412)).

## 28.5.0 (2024-08-07)

### Bug Fixes
Expand Down
125 changes: 125 additions & 0 deletions packages/components/src/custom-select-control/test/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -689,3 +689,128 @@ describe.each( [
} );
} );
} );

describe( 'Type checking', () => {
// eslint-disable-next-line jest/expect-expect
it( 'should infer the value type from available `options`, but not the `value` or `onChange` prop', () => {
const options = [
{
key: 'narrow',
name: 'Narrow',
},
{
key: 'value',
name: 'Value',
},
];
const optionsReadOnly = [
{
key: 'narrow',
name: 'Narrow',
},
{
key: 'value',
name: 'Value',
},
] as const;

const onChange = (): void => {};

<UncontrolledCustomSelectControl
label="Label"
options={ options }
value={ {
key: 'narrow',
name: 'Narrow',
} }
onChange={ onChange }
/>;

<UncontrolledCustomSelectControl
label="Label"
options={ options }
value={ {
key: 'random string is also accepted for non-readonly options',
name: 'Narrow',
} }
onChange={ onChange }
/>;

<UncontrolledCustomSelectControl
label="Label"
options={ options }
value={ {
key: 'narrow',
name: 'Narrow',
// @ts-expect-error: the option type should not be inferred from `value`
foo: 'foo',
} }
onChange={ onChange }
/>;

<UncontrolledCustomSelectControl
label="Label"
options={ options }
value={ {
key: 'narrow',
name: 'Narrow',
} }
// To ensure the type inferring is working correctly, but this is not a common use case.
// @ts-expect-error: the option type should not be inferred from `onChange`
onChange={
onChange as ( obj: {
selectedItem: { key: string; name: string; foo: string };
} ) => void
}
/>;

<UncontrolledCustomSelectControl
label="Label"
options={ optionsReadOnly }
value={ {
key: 'narrow',
name: 'Narrow',
} }
onChange={ onChange }
/>;

<UncontrolledCustomSelectControl
label="Label"
options={ optionsReadOnly }
value={ {
// @ts-expect-error: random string is not accepted for immutable options
key: 'random string is not accepted for readonly options',
name: 'Narrow',
} }
onChange={ onChange }
/>;

<UncontrolledCustomSelectControl
label="Label"
options={ optionsReadOnly }
value={ {
key: 'narrow',
name: 'Narrow',
// @ts-expect-error: the option type should not be inferred from `value`
foo: 'foo',
} }
onChange={ onChange }
/>;

<UncontrolledCustomSelectControl
label="Label"
options={ optionsReadOnly }
value={ {
key: 'narrow',
name: 'Narrow',
} }
// To ensure the type inferring is working correctly, but this is not a common use case.
// @ts-expect-error: the option type should not be inferred from `onChange`
onChange={
onChange as ( obj: {
selectedItem: { key: string; name: string; foo: string };
} ) => void
}
/>;
} );
} );
6 changes: 3 additions & 3 deletions packages/components/src/custom-select-control/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export type CustomSelectProps< T extends CustomSelectOption > = {
* Function called with the control's internal state changes. The `selectedItem`
* property contains the next selected item.
*/
onChange?: ( newValue: CustomSelectChangeObject< T > ) => void;
onChange?: ( newValue: CustomSelectChangeObject< NoInfer< T > > ) => void;
/**
* A handler for `blur` events on the trigger button.
*
Expand Down Expand Up @@ -83,7 +83,7 @@ export type CustomSelectProps< T extends CustomSelectOption > = {
/**
* The list of options that can be chosen from.
*/
options: Array< T >;
options: ReadonlyArray< T >;
/**
* The size of the control.
*
Expand All @@ -93,7 +93,7 @@ export type CustomSelectProps< T extends CustomSelectOption > = {
/**
* Can be used to externally control the value of the control.
*/
value?: T;
value?: NoInfer< T >;
/**
* Use the `showSelectedHint` property instead.
* @deprecated
Expand Down

0 comments on commit 8169dfd

Please sign in to comment.