[select] Broken `value` type inference on Select wrapper component
Bug report
Current behavior
After upgrading to version 1.0.0-beta.6, the Select component incorrectly infers its value type. With an approach that closely resembles the one in these docs:
function MySelect<Value, Multiple extends boolean | undefined = false>(
props: SelectRootProps<Value, Multiple>
) {
return <Select.Root {...props} />
}
I am getting the following error in Select.Root:
No overload matches this call.
Overload 1 of 2, '(props: SelectRootControlledProps<Value, Multiple>): Element', gave the following error.
Type '{ children?: ReactNode; inputRef?: Ref<HTMLInputElement> | undefined; name?: string | undefined; id?: string | undefined; required?: boolean | undefined; ... 15 more ...; onValueChange?: ((value: SelectValueType<...>, eventDetails: SelectRootChangeEventDetails) => void) | undefined; } | { ...; }' is not assignable to type 'IntrinsicAttributes & Omit<SelectRootCommonProps<Value>, "multiple" | "value" | "defaultValue" | "onValueChange"> & { ...; } & { ...; }'.
Type '{ children?: ReactNode; inputRef?: Ref<HTMLInputElement> | undefined; name?: string | undefined; id?: string | undefined; required?: boolean | undefined; ... 15 more ...; onValueChange?: ((value: SelectValueType<...> | (Multiple extends true ? never : null), eventDetails: SelectRootChangeEventDetails) => void) | und...' is not assignable to type '{ value: SelectValueType<Value, Multiple>; onValueChange?: ((value: SelectValueType<Value, Multiple>, eventDetails: SelectRootChangeEventDetails) => void) | undefined; }'.
Property 'value' is optional in type '{ children?: ReactNode; inputRef?: Ref<HTMLInputElement> | undefined; name?: string | undefined; id?: string | undefined; required?: boolean | undefined; ... 15 more ...; onValueChange?: ((value: SelectValueType<...> | (Multiple extends true ? never : null), eventDetails: SelectRootChangeEventDetails) => void) | und...' but required in type '{ value: SelectValueType<Value, Multiple>; onValueChange?: ((value: SelectValueType<Value, Multiple>, eventDetails: SelectRootChangeEventDetails) => void) | undefined; }'.
Overload 2 of 2, '(props: SelectRootUncontrolledProps<Value, Multiple>): Element', gave the following error.
Type '{ children?: ReactNode; inputRef?: Ref<HTMLInputElement> | undefined; name?: string | undefined; id?: string | undefined; required?: boolean | undefined; ... 15 more ...; onValueChange?: ((value: SelectValueType<...>, eventDetails: SelectRootChangeEventDetails) => void) | undefined; } | { ...; }' is not assignable to type 'IntrinsicAttributes & Omit<SelectRootCommonProps<Value>, "multiple" | "value" | "defaultValue" | "onValueChange"> & { ...; } & { ...; }'.
Type '{ children?: ReactNode; inputRef?: Ref<HTMLInputElement> | undefined; name?: string | undefined; id?: string | undefined; required?: boolean | undefined; ... 15 more ...; onValueChange?: ((value: SelectValueType<...>, eventDetails: SelectRootChangeEventDetails) => void) | undefined; }' is not assignable to type '{ value?: any; onValueChange?: ((value: SelectValueType<Value, Multiple> | (Multiple extends true ? never : null), eventDetails: SelectRootChangeEventDetails) => void) | undefined; }'.
Types of property 'onValueChange' are incompatible.
Type '((value: SelectValueType<Value, Multiple>, eventDetails: SelectRootChangeEventDetails) => void) | undefined' is not assignable to type '((value: SelectValueType<Value, Multiple> | (Multiple extends true ? never : null), eventDetails: SelectRootChangeEventDetails) => void) | undefined'.
Type '(value: SelectValueType<Value, Multiple>, eventDetails: SelectRootChangeEventDetails) => void' is not assignable to type '(value: SelectValueType<Value, Multiple> | (Multiple extends true ? never : null), eventDetails: SelectRootChangeEventDetails) => void'.
Types of parameters 'value' and 'value' are incompatible.
Type 'SelectValueType<Value, Multiple> | (Multiple extends true ? never : null)' is not assignable to type 'SelectValueType<Value, Multiple>'.
Type 'Multiple extends true ? never : null' is not assignable to type 'SelectValueType<Value, Multiple>'.
Type 'null' is not assignable to type 'SelectValueType<Value, Multiple>'.
Type 'null' is not assignable to type 'Value'.
'Value' could be instantiated with an arbitrary type which could be unrelated to 'null'.
Expected behavior
The type of the value property should be correctly inferred.
Reproducible example
Link to CodeSandbox: https://codesandbox.io/p/sandbox/rypm33
Base UI version
v1.0.0-beta.6
Which browser are you using?
Chrome
Those docs were added as part of the refactor in #3254 to simplify typed wrappers to ensure they're easy to make. It's not part of beta.6 yet, it'll be in the next version.
A workaround for the current version is to specify value after the spread:
export function MySelect<Value, Multiple extends boolean | undefined = false>(
props: Select.Root.Props<Value, Multiple>
): React.JSX.Element {
return (
<Select.Root {...props} value={props.value}>
{/* ... */}
</Select.Root>
);
}
Or install the preview release in the meantime until the next version is on npm, which has typesafety:
pnpm add https://pkg.pr.new/mui/base-ui/@base-ui-components/react@3254
@atomiks Should we close this one, given that the next release will have the mentioned improvement? 🤔
This fix will be available in the next npm release of Base UI.
In the meantime, you can try it out on our Canary release channel:
npm i https://pkg.pr.new/@base-ui-components/react@3331