Ivanf
Ivanf

Reputation: 61

Create a typescript function returning react component class

I need to create an utility function, which will be returning one of react component classes (not instances) depending on some condition. So the return type of the function should be generic (React.PureComponent)

import React from 'react';
class FooOne extends React.PureComponent {
    render(): React.ReactElement {
        return null;
    }
}
class FooTwo extends React.PureComponent {
    render(): React.ReactElement {
        return null;
    }
}
function getFooClass(condition: boolean): typeof React.PureComponent {
    return condition ? FooOne : FooTwo;
}
const SomeFooClass = getFooClass(true);
const instance: React.PureComponent = new SomeFooClass();

code above is tended to be working (I still not understand why I need to use typeof React.PureComponent as return type for getFooClass, this was found experimentally), but typescript generates the following error for getFooClass:

Type 'typeof FooOne' is not assignable to type 'typeof PureComponent'.
  Construct signature return types 'FooOne' and 'PureComponent<P, S>' are incompatible.
    The types of 'props' are incompatible between these types.
      Type 'Readonly<{ children?: ReactNode; }> & Readonly<{}>' is not assignable to type 'Readonly<{ children?: ReactNode; }> & Readonly<P>'.
        Type 'Readonly<{ children?: ReactNode; }> & Readonly<{}>' is not assignable to type 'Readonly<P>'.

Maybe this is kind of typescript bug or limitation?

Upvotes: 4

Views: 8187

Answers (2)

Amadare42
Amadare42

Reputation: 414

Try something like

function getFooClass(condition: boolean): React.ComponentType {
   // if FooOne and FooTwo have arguments you can use React.ComponentType<TArgs>
   return condition ? FooOne : FooTwo;
}

usage should be like this

function render() {
    const FooEl = getFooClass(true); // PascalCase is required
    return <FooEl />
}

or simply return created instance

function getFooClass(condition: boolean): JSX.Element  {
   return condition ? <FooOne /> : <FooTwo />;
}

Upvotes: 4

Jonathan Irwin
Jonathan Irwin

Reputation: 5747

React.ReactNode should work in this case:

function getFooClass(condition: boolean): React.ReactNode {
  return condition ? FooOne : FooTwo;
}

Upvotes: 2

Related Questions