// 1. cant use React.ComponentType else we loose generics const withStuff = <TProps,>(Component: (props: TProps) => React.ReactNode) => { const stuff = useStuff(); return (props: Omit<TProps, 'stuff'>) => { // 2. gotta use `as` here, I know it's annoying return <Component {...(props as TProps)} stuff={stuff} />; }; }; type MyComponentProps<T> = { stuff: Stuff; items: T[]; defaultItem: T; }; const MyComponent = <T extends React.ReactNode>(props: MyComponentProps<T>) => { return ( <div> {props.items.map((item) => ( <div>{item}</div> ))} </div> ); }; const StuffedComponent = withStuff(MyComponent); <> <StuffedComponent items={[1, 2, 3]} defaultItem={1} /> {/* 3. defaultItem is inferred to be 1 | 2 | 3 */} </>;
This is the same trick we used to get nicer forwardRef
here.