I have Tree component, which renders TreeItemsRenderer that draws TreeItem. Each of them are seperate components.
I need to accept dynamic component that replaces default TreeItem, and I need to have all default TreeItem props. (for ex: const CustomComponent extends TreeItem). Tree is used in many places in code. So it needs to be generic.
- I tried to get all properties from default TreeItem by creating generic type
D extends ITreeItemProps<T>
. T
generic is for item type.- All of autocompletion works from outside. Only error is on TreeItemRenderer component with rendering SelectedRowComponent.
here is my components (It may be illogical at some moments, because I deleted unneccesary stuff and simplified logic):
Tree :
import { ITreeItemProps, ITreeItem } from "./types";
import TreeItemRenderer from "./TreeItemRenderer";
export interface ITreeProps<T, D extends ITreeItemProps<T>> {
items: ITreeItem<T>[];
getItemKey: (item: T) => string | number;
SelectedRowComponent?: React.ComponentType<D>;
SelectedRowProps?: Partial<React.ComponentProps<ITreeProps<T, D>['SelectedRowComponent'] & {}>>;
selected?: string | number;
}
export default function Tree<T, D extends ITreeItemProps<T>>(props: ITreeProps<T, D>){
const {
items,
SelectedRowComponent,
SelectedRowProps,
getItemKey,
selected,
} = props;
return <>
<TreeItemRenderer
getItemKey={getItemKey}
items={items}
SelectedRowComponent={SelectedRowComponent}
SelectedRowProps={SelectedRowProps}
selected={selected}
/>
</>
}
TreeItemRenderer:
import { ITreeItemProps, ITreeItem } from "./types";
import TreeItem from './TreeItem';
export interface ITreeItemRenderer<T, D extends ITreeItemProps<T>>{
getItemKey: (item: T) => string | number;
SelectedRowComponent?: React.ComponentType<D>
SelectedRowProps?: Partial<React.ComponentProps<ITreeItemRenderer<T, D>['SelectedRowComponent'] & {}>>;
items: ITreeItem<T>[];
selected?: string | number;
}
export default function TreeItemRenderer<T, D extends ITreeItemProps<T>>(props: ITreeItemRenderer<T, D>){
const {
SelectedRowComponent,
SelectedRowProps,
items,
selected,
getItemKey,
} = props;
return <>
{items.map((item) => {
const key = getItemKey(item);
const isSelected = key === selected;
return <>
{
isSelected ?
<SelectedRowComponent
{...SelectedRowProps}
item={item}
getItemKey={getItemKey}
isSelected
/>
: <TreeItem
item={item}
getItemKey={getItemKey}
isSelected
/>
}
</>
})}
</>
}
Types component:
export interface ITreeItemProps<T> {
getItemKey: (item: T) => string | number;
isSelected: boolean;
item: ITreeItem<T>;
}
export type ITreeItem<T> = T & {
children: ITreeItem<T>[];
};
And my problem is in TreeItemRenderer on line 28
Type '(Partial<D> & { item: ITreeItem<T>; getItemKey: (item: T) => string | number; isSelected: true; }) | (Partial<D & { children?: ReactNode; }> & { ...; })' is not assignable to type 'IntrinsicAttributes & D & { children?: ReactNode; }'.
Type 'Partial<D> & { item: ITreeItem<T>; getItemKey: (item: T) => string | number; isSelected: true; }' is not assignable to type 'IntrinsicAttributes & D & { children?: ReactNode; }'.
Type 'Partial<D> & { item: ITreeItem<T>; getItemKey: (item: T) => string | number; isSelected: true; }' is not assignable to type 'D'.
'Partial<D> & { item: ITreeItem<T>; getItemKey: (item: T) => string | number; isSelected: true; }' is assignable to the constraint of type 'D', but 'D' could be instantiated with a different subtype of constraint 'ITreeItemProps<T>'.ts(2322)