I want to make a function which will return typeof React Component, which must implement a specific props interface.
I want to return a type, not an instance of that type.
So given this:
interface INameProps {
name: string;
}
interface ITypeProps {
type: string;
}
class Component1 extends React.Component<INameProps> {}
class Component2 extends React.Component<INameProps> {}
class Component3 extends React.Component<ITypeProps> {}
I would like to make a function, that could return components, for which the props interface extends INameProps
So far I figured this out:
export function getComponents<T extends INameProps, S extends any>(): React.Component<T, S> {
return Component1; // should be fine
return Component2; // should be fine
return Component3; // should not be allowed, since T for Component3 does not extend INameProps
}
But this is not correct - return type of this function is an instance of those components.
To get a type, I would think I would just have to add typeof
keyword like so:
export function getComponents<T extends INameProps, S extends any>(): typeof React.Component<T, S>
But TypeScript does not like, that I add generics <T, S>
after React.Component.
It compiles, when I define it like this:
export function getComponents<T extends INameProps, S extends any>(): typeof React.Component
But this does not do what I want - return type of function like this is a type of any React.Component.
How do I write this?
EDIT:
I went looking around, and found React.ComponentType (For Flow, I didn't see any documentation for TypeScript tho)
Turns out, the answer is rather simple. I was trying to come up with my own way using advanced types of TypeScript, but React already thought of this -
export function getComponent(): React.ComponentType<INameProps> {
return Component1; // allowed
return Component2; // allowed
return Component3; // not allowed, since props for Component3 does not extend INameProps
}
return Component1
gives you the constructor function, not an instance, it's the closest you get to the type of an instance. TypeScript types are compile-time only and not something you can pass around like a value at run-time. I think what you have is probably what you want. You should be able to e.g.<ReturnedComponent/>
in a tsx to actually instantiate the component. – dezfowler