1
interface Props {
    component: any;
}
function Example(props: Props) {
    const {component: Component, children} = props
    return <Component>{children}</Component>
}

For example: the incoming component is TouchableOpacity in react-native, then the Example component automatically inherits all Props of TouchableOpacity. You can write like this and Typescript does not report errors:

<Example component={TouchableOpacity} onPress={handleSomePress} />

I am a newbie to TypeScript, this problem has bothered me for a long time. Looking forward to a perfect answer, pray.

fly-web
  • 13
  • 3
  • You will need to use a generic type and utilise `React.ComponentType<>` and `React.ComponentProps<>`. Example: [https://stackblitz.com/edit/react-ts-nbcomt?file=index.tsx](https://stackblitz.com/edit/react-ts-nbcomt?file=index.tsx) – Jacob Smit Sep 29 '20 at 03:47
  • I added comments to the example above. – Jacob Smit Sep 29 '20 at 03:55
  • Thank you very much for your answer, I will try it right away and I will get back to you later – fly-web Sep 29 '20 at 03:57
  • The type "Element" cannot be assigned to the type "TestProps". The attribute "component" is missing in the type "Element", but it is required in the type "{ component: TComponent; }". Typescript reported this error – fly-web Sep 29 '20 at 04:25
  • Do you have a code sample you could share? – Jacob Smit Sep 29 '20 at 04:29

1 Answers1

0

You will have to use generics and get Typescript to infer the properties based off the component you assign.

// Prop type for wrapper component
type WrapperProps<TComponent extends React.ComponentType<any> = any> = 
  // component prop will be used to both pass the component to render
  // and to get the Typing for the component, once the component is assigned
  // Typescript will infer TComponent and propagate it thoughout the rest of
  // the type.
  { component: TComponent; } & 
  // Add all the props from the passed in component.
  React.ComponentProps<TComponent>;

// Create the component.
// The component must pass the generics as well otherwise they will be defaulted
// to any and no infered typing will occur.
const Wrapper = <TComponent extends React.ComponentType<any> = any>({
  // Get component from props.
  component,
  // Get the rest of the passed in props
  ...restProps
}: WrapperProps<TComponent>) => {

  // To render a custom component the variable must start with a capital. 
  const Component = component;

  // Here you could modify or remove props that have been passed in,
  // or apply defaults to missing props etc.

  // Render component with props.
  return <Component {...restProps} />;
};

Runnable Example

Jacob Smit
  • 2,206
  • 1
  • 9
  • 19
  • I have encountered a new problem, that is, when I use React.memo(Wrapper) like this, Typescript will not infer TComponent and propagate it thoughout the rest of the type, what should I do? – fly-web Sep 29 '20 at 05:01
  • I'll take a look at correcting the `React.memo` type when I have a spare second, but my assumption is you would have to retype the output that comes from `React.memo`. On a side note, do you actually need to use `React.memo`? `React.memo` will make function components act more like class components with a `shouldComponentUpdate`, depending on your use case this can be better handled in function components using hooks that can nitpick what should be memoize and what is quick enough to recalculate. I'm not saying don't use it, just saying make sure you are using it for the right reason. – Jacob Smit Sep 29 '20 at 05:13
  • I found a [github issue](https://github.com/DefinitelyTyped/DefinitelyTyped/issues/37087) / another [stack overflow question](https://stackoverflow.com/questions/56891234/reacts-memo-drops-generics-in-the-returned-function?noredirect=1#comment100573160_56891234) and the best solution I could see at the moment is to redo the types for `React.useMemo` I have updated the runnable example. – Jacob Smit Sep 29 '20 at 05:36
  • Yes, but I solved the problem in the following way: export const typedMemo: (c: T, propsAreEqual?: (prevProps: Readonly>, nextProps: Readonly>) => boolean) => T = memo; – fly-web Sep 29 '20 at 06:56