I'm experimenting with extending components in React. I'm trying to extend Handsontable using forwardRef and useImperativeHandle. First I wrap Handsontable in my own BaseTable component, adding some methods. Then I extend the BaseTable in a CustomersTable component in the same way to add even more methods and behavior. Everything seems to work well until I try to consume the CustomersTable in CustomersTableConsumer where I get some type errors. The component works just fine, it's just Typescript that isn't happy.
BaseTable:
export type BaseTableProps = {
findReplace: (v: string, rv: string) => void;
} & HotTable;
export const BaseTable = forwardRef<BaseTableProps, HotTableProps>(
(props, ref) => {
const hotRef = useRef<HotTable>(null);
const findReplace = (value: string, replaceValue: string) => {
const hot = hotRef?.current?.__hotInstance;
// ...
};
useImperativeHandle(
ref,
() =>
({
...hotRef?.current,
findReplace
} as BaseTableProps)
);
const gridSettings: Handsontable.GridSettings = {
autoColumnSize: true,
colHeaders: true,
...props.settings
};
return (
<div>
<HotTable
{...props}
ref={hotRef}
settings={gridSettings}
/>
</div>
);
}
);
CustomersTable:
export type CustomerTableProps = HotTable & {
customerTableFunc: () => void;
};
export const CustomersTable = forwardRef<CustomerTableProps, BaseTableProps>(
(props, ref) => {
const baseTableRef = useRef<BaseTableProps>(null);
const customerTableFunc = () => {
console.log("customerTableFunc");
};
useImperativeHandle(
ref,
() =>
({
...baseTableRef?.current,
customerTableFunc
} as CustomerTableProps)
);
useEffect(() => {
const y: Handsontable.ColumnSettings[] = [
{
title: "firstName",
type: "text",
wordWrap: false
},
{
title: "lastName",
type: "text",
wordWrap: false
}
];
baseTableRef?.current?.__hotInstance?.updateSettings({
columns: y
});
}, []);
return <BaseTable {...props} ref={baseTableRef} />;
}
);
CustomerTableConsumer:
export const CustomerTableConsumer = () => {
const [gridData, setGridData] = useState<string[][]>([]);
const customersTableRef = useRef<CustomerTableProps>(null);
const init = async () => {
const z = [];
z.push(["James", "Richard"]);
z.push(["Michael", "Irwin"]);
z.push(["Solomon", "Beck"]);
setGridData(z);
customersTableRef?.current?.__hotInstance?.updateData(z);
customersTableRef?.current?.customerTableFunc();
customersTableRef?.current?.findReplace("x", "y"); };
useEffect(() => {
init();
}, []);
// can't access extended props from handsontable on CustomersTable
return <CustomersTable data={gridData} ref={customersTableRef} />;
};
Here is a Codesandbox example.
How do I need to update my typings to satisfy Typescript in this scenario?
import HotTable, { HotTableProps } from "@handsontable/react";
Andexport type CustomerTableProps = { customerTableFunc: () => void; } & HotTable;
fixed the first issue – Accursed