javascript - Getting TypeScript to Infer Props Correctly for a Nested Generic Function Component - Stack Overflow

The title will make more sense with an example:I have the following component GlobalDialog:export typ

The title will make more sense with an example:

I have the following component GlobalDialog:

export type GlobalDialogProps<T extends React.FunctionComponent<any>> = {
    Trigger: React.FunctionComponent<{ onToggle: () => void; }>;
    Panel: T;
    panelProps: ComponentProps<T>;
    zIndex: number;
};

export default function GlobalDialog<T extends React.FunctionComponent<any>>(props: GlobalDialogProps<T>) {
    // Implementation details
}

and component FilterProductResultsControllerV2

export default function FilterProductResultsControllerV2<T extends React.FC<any>>(props: { ResultElement: T; propsFactory: (product: IProduct) => ComponentProps<T>; }) {
    // Implementation details
}

I then try to pass FilterProductResultsControllerV2 as a Panel to my Global Dialog, and propsFactory ends up being inferred as (product: IProduct) => any instead of (product: IProduct) => CountTrackerProductProps

<GlobalDialog
    zIndex={10}
    Trigger={({ onToggle }) => (
        // Implementation detail
    )}
    Panel={FilterProductResultsControllerV2}
    panelProps={{
        renderAs: "panel",
        ResultElement: CountTrackerProduct,
        propsFactory: (product) => {
            const orderItemData = value[product.id];

            return {
                product: product,
                onAdd: () => addOrderItem(product),
                quantity: orderItemData?.quantity ?? null,
            };
        },
    }}
/>

where CountTrackerProduct is:

type CountTrackerProductProps = { product: IProduct; onAdd: () => void; quantity: number | null; };

export default function CountTrackerProduct(props: CountTrackerProductProps) { 
    // Implementation details
}

A working solution to this problem is using FilterProductResultsControllerV2<typeof CountTrackerProduct> as Panel, but it's not the most elegant one either.

So my question is, why exactly does this happen in Typescript? and are there any ways around it, if any?

Full Sample Code that features the issue

import { useState } from "react";
    
interface IProduct {
    id: string;
    name: string;
}

type GlobalDialogProps<T extends React.FunctionComponent<any>> = {
    Trigger: React.FunctionComponent<{ onToggle: () => void }>;
    Panel: T;
    panelProps: React.ComponentProps<T>;
    zIndex: number;
};

function GlobalDialog<T extends React.FunctionComponent<any>>(props: GlobalDialogProps<T>) {
    const [open, setOpen] = useState(false);
    const { Panel, panelProps, Trigger } = props;
    return (
        <>
            <Trigger onToggle={() => setOpen(!open)} />
            {/*<Panel {...panelProps} /> */}
        </>
    );
}

function FilterProductResultsControllerV2<T extends React.FC<any>>(props: { ResultElement: T; propsFactory: (product: IProduct) => React.ComponentProps<T> }) {
    return <div></div>;
}

type CountTrackerProductProps = {
    product: IProduct;
    onAdd: () => void;
    quantity: number | null;
};

function CountTrackerProduct(props: CountTrackerProductProps) {
    return <div></div>;
}

function OrderItemDataWidget() {
    const [value, setValue] = useState<Record<IProduct["id"], { quantity: number }>>({});
    const addOrderItem = (product: IProduct) => console.log(`added product ${product.id}`);

    return (
        <div>
            <div>close off</div>
            <GlobalDialog
                zIndex={10}
                Trigger={({ onToggle }) => <button onClick={onToggle} type="button">dummy</button>}
                Panel={FilterProductResultsControllerV2}
                panelProps={{
                    ResultElement: CountTrackerProduct,
                    propsFactory: (product) => {
                        const orderItemData = value[product.id];

                        return {
                            product: product,
                            onAdd: () => addOrderItem(product),
                            quantity: orderItemData?.quantity ?? null,
                        };
                    },
                }}
            />
        </div>
    );
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745253332a4618807.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信