1

I have TypeScript code such as the following:

interface Props<T> {}

function HOC<P>(component: React.ComponentType<P>): React.ComponentType<P> {
  return component;
}

const MyClass = HOC(class MyClass<T> extends React.Component<Props<T>, {}> {});
type MyClass<T> = React.ComponentType<Props<T>>;

function render() {
  return <MyClass<string> />;
}

But this doesn't work because I get the following errors on the line with MyClass<string>:

[ts]
JSX element type 'ReactElement<any> | null' is not a constructor function for JSX elements.
  Type 'null' is not assignable to type 'ElementClass'.
[ts] Expected 0 type arguments, but got 1.

If I remove the HOC and the type declaration, it compiles fine:

interface Props<T> {}

class MyClass<T> extends React.Component<Props<T>, {}> {};

function render() {
  return <MyClass<string> />;
}

So my question is, assuming that I can't modify the type declaration of HOC, how can I declare the const MyClass (with a type MyClass<T> if necessary) such that the first example will compile successfully?

June Rhodes
  • 3,047
  • 4
  • 23
  • 29
  • If you don't like writing a type assertion that could potentially get out of date as the code changes and hide problems, see [this answer](https://stackoverflow.com/a/52573647) for another approach. – Matt McCutchen Oct 10 '18 at 13:53

1 Answers1

3

You will need to use a type assertion to let the typescript compiler now that MyClass is a generic constructor:

interface Props<T> {
  prop: T
}

function HOC<P>(component: React.ComponentType<P>): React.ComponentType<P> {
  return component;
}

const MyClass = HOC(class MyClass<T> extends React.Component<Props<T>, {}> {}) as {
  new <T>(props: Props<T>, context?: any): React.Component<Props<T>> // Generic constructor
}

function render() {
  return <MyClass<string> prop="" />;
}

function render2() {
  return <MyClass<number> prop={1} />;
}

Note As far as I know typescript lacks the ability to model the kind of generic type transformation you are looking for unfortunately, even if you could change the HOC.

Titian Cernicova-Dragomir
  • 230,986
  • 31
  • 415
  • 357