I'm using TypeScript 3.4.5 and Material UI 4.2 and with the following piece of code:
interface MyItemProps {
name: string;
value: string;
}
function Item({ name, value, ...props }: ListItemProps<'li', MyItemProps>): ReactElement {
return (
<ListItem {...props} className="item">
<ListItemText primary={name} secondary={value || '-'} />
</ListItem>
);
}
I'm getting Type 'boolean' is not assignable to type 'true'
error. Why?
I've been looking into the type definitions for ListItem
, but I can't figure out what's going on:
export interface ListItemTypeMap<P, D extends React.ElementType> {
props: P & {
alignItems?: 'flex-start' | 'center';
autoFocus?: boolean;
button?: boolean;
ContainerComponent?: React.ElementType<React.HTMLAttributes<HTMLDivElement>>;
ContainerProps?: React.HTMLAttributes<HTMLDivElement>;
dense?: boolean;
disabled?: boolean;
disableGutters?: boolean;
divider?: boolean;
focusVisibleClassName?: string;
selected?: boolean;
};
defaultComponent: D;
classKey: ListItemClassKey;
}
declare const ListItem: OverridableComponent<ListItemTypeMap<{ button?: false }, 'li'>> &
ExtendButtonBase<ListItemTypeMap<{ button: true }, 'div'>>;
export type ListItemClassKey =
| 'root'
| 'container'
| 'focusVisible'
| 'default'
| 'dense'
| 'disabled'
| 'divider'
| 'gutters'
| 'button'
| 'secondaryAction'
| 'selected';
export type ListItemProps<D extends React.ElementType = 'li', P = {}> = OverrideProps<
ListItemTypeMap<P, D>,
D
>;
export default ListItem;
The only thing that comes to my mind is "type widening", but I don't really know what's happening and why.
Could somebody please explain what's going on? Most importantly, what is the correct way of extending a Material UI component?
The Stack component manages layout of immediate children along the vertical or horizontal axis with optional spacing and/or dividers between each child.
According to https://mui.com/material-ui/api/button/ , it means "The component used for the root node. Either a string to use a HTML element or a component.".
To be able to use props of such a MUI component on their own, props should be used with type arguments. Otherwise, the component prop will not be present in the props of the MUI component. The examples below use TypographyProps but the same will work for any component which has props defined with OverrideProps .
import {} from '@material-ui/core'; import {} from '@material-ui/icons'; import {} from '@mui/material'; A better optimized approach, is to create a single file in your project where you import each component that you use individually, then export them all under a single namespace: // src/mui/index.
This appears to be a well established issue over on the material-ui github. Apparently it stems from using booleans to do union discrimination - I'm still new to TS so only have a general understanding of what that means!
The cleanest way to get past this which I found from those threads (without overwriting button
with explicit any
in the component props, ew) is by casting button
as true directly on to the ListItem
:
interface MyItemProps {
name: string;
value: string;
}
type MyListItem = ListItemProps<"li", MyItemProps>;
function Item({ name, value, button, ...props }: MyListItem): ReactElement {
return (
<ListItem {...props} className="item" button={button as true}>
<ListItemText primary={name} secondary={value || '-'} />
</ListItem>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With