Home > Back-end >  MUI customize Select in TS
MUI customize Select in TS

Time:08-27

What is wrong in the following code?

TS2322: Type '(event: SelectChangeEvent) => void' is not assignable to type '(event: SelectChangeEvent<unknown>, child: ReactNode) => void'.   Types of parameters 'event' and 'event' are incompatible.
     Type 'SelectChangeEvent<unknown>' is not assignable to type 'SelectChangeEvent<string>'.
       Type 'Event & { target: { value: unknown; name: string; }; }' is not assignable to type 'SelectChangeEvent<string>'.
         Type 'Event & { target: { value: unknown; name: string; }; }' is not assignable to type 'Event & { target: { value: string; name: string; }; }'.
           Type 'Event & { target: { value: unknown; name: string; }; }' is not assignable to type '{ target: { value: string; name: string; }; }'.             The types of 'target.value' are incompatible between these types.
               Type 'unknown' is not assignable to type 'string'.


 Select.d.ts(104, 3): The expected type comes from property 'onChange' which is declared here on type 'IntrinsicAttributes & { items: { children: ReactNode; props: MenuItemProps<"li", {}>; }[]; } & SelectProps<unknown>'

import * as React from 'react';
import MuiSelect, {SelectProps as MuiSelectProps} from '@mui/material/Select';
import MuiMenuItem, {MenuItemProps as MuiMenuItemProps} from '@mui/material/MenuItem';


export type SelectProps<T = unknown> = {
    items: {
        children: React.ReactNode,
        props: MuiMenuItemProps,
    }[],
} & MuiSelectProps<T>;

const Select: React.FC<SelectProps> = ({items, ...props}) => {
    return (
        <MuiSelect
            {...props}
        >
            {
                items.map((item, index) => (
                    <MuiMenuItem key={item.props.key ?? index} {...item.props}>{item.children}</MuiMenuItem>
                ))
            }
        </MuiSelect>
    );
};

export default Select;

This is the onChange prop

const handleChange = (event: SelectChangeEvent) => {
        // Some logic
    };

CodePudding user response:

Calling SelectChangeEvent with no type parameter will result in the default value, string (see below), which is not compatible with the inferred type unknown - what you get when calling your Select component. You can fix this by using SelectChangeEvent<unknown> in handleChange.


Explanation

The trouble T type parameter passed to MuiSelectProps is the culprit. Looking at Select.d.ts, T is used here:

  onChange?: SelectInputProps<T>['onChange'];

Which points to

/**
 * The change can be caused by different kind of events.
 * The type of event depends on what caused the change.
 * For example, when the browser auto-fills the `Select` 
you'll receive a `React.ChangeEvent`.
 */
export type SelectChangeEvent<T = string> =
  | (Event & { target: { value: T; name: string } })
  | React.ChangeEvent<HTMLInputElement>;

export interface SelectInputProps<T = unknown> {
  // ...
  onChange?: (event: SelectChangeEvent<T>, child: React.ReactNode) => void;

So when you call SelectChangeEvent sans a type parameter, it defaults to string while unknown is inferred as the default type parameter for all the parent usages.

Here's a playground with this.

  • Related