edit: link to playground https://tsplay.dev/NBJ0zN
i'm creating a hook that is supposed to return a modal component, the hook can take a generic to add some extra typings to the body component i inject inside this hook
i have 2 types that look somewhat like this :
export type DefaultBodyComponentProps= { onClose: ()=> void; };
the onClose funcion comes from inside the hook
export type ConnectModalConfig<B extends object> = {
bodyComponent?: React.ComponentType<B & DefaultBodyProps>;
};
the modal component returned by this hook is supposed to take an object called bodyProps with some props i can inject inside the body component
export type ModalProps<B> = { bodyProps?: B; };
the way i use this hook is like this
const [Modal, modalActions] = useConnectedModal<BodyProps>({
bodyComponent: Body,
});
and the modal component
<Modal bodyProps={..somePropsOfTypeBodyProps}/>
the modal component inside the hook looks like this
export default function useConnectedModal<B extends object = object>(
props: ConnectModalConfig<B>,
) {
const { bodyComponent: BodyComponent = DefaultBodyComponent } = props;
//logic
const Modal = (props: ModalProps<B>) => {
const { bodyProps } = props;
const onClose = () => {
//logic
};
return (
<Wrapper>
<BodyComponent {...bodyProps} onClose={onClose} />{' '}
</Wrapper>
);
};
return [Modal];
}
but i get this typescript error that says :
Type '{ onClose: () => void; }' is not assignable to type 'B'. '{ onClose: () => void; }' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtype of constraint 'object'.
I understand what it means but i can't seem to be able to solve it xD
Any tips ?
In the end i solved it by casting bodyProps as B
<BodyComponent {...bodyProps as B} onClose={onClose} />
not important to my question but i also ended up wanting bodyProps to stay optional so i did this utility type
type RequirePropsIfAdditionalPropsExist<T, T2 extends string> = keyof Omit<
T,
'onClose'
> extends never
? { [K in T2]?: never }
: { [K in T2]: Omit<T, 'onClose'> };
export type ModalProps<B, F, H> = RequirePropsIfAdditionalPropsExist<
B,
'bodyProps'
> &
RequirePropsIfAdditionalPropsExist<H, 'headerProps'> &
RequirePropsIfAdditionalPropsExist<F, 'footerProps'> & {
onClose?: OnClose;
};
that way when i call the component if i passed something else in the generic other than onClose ts will give me a warning