TSX doesn't seem to play well with type arguments in props.

You should set a default type param value, such as any, but that will just assume your types are always any when using the component, which might not be exactly what you want:

export interface Props<T = any> {
  value: T;
  valueCallback: (t: T) => void;

// ...

// `valueCallback` will pass an explicit `any`
<TypedComponent value={value} valueCallback={setState} />

You could try copying it with the valid extended type, and then using that, e.g.:

import { Props as TCProps } from './TypedComponent'
const StronglyTypedComponent: React.Component<TCProps<string>> = TypedComponent

// ...

// correctly typed, but more verbal
<StronglyTypedComponent value={value} valueCallback={setState} /> 


Not the ideal solution, but I was able to achieve this by exporting the component's type, and then using that to cast the result of React.lazy

export type TypedComponentType = typeof TypedComponent;

And then

import type { TypeComponent } from './TypedComponent';
const TypedComponent = lazy(() => import("./TypedComponent")) as TypedComponentType;


TL;DR: You can override React.lazy type definition to support generics.


declare namespace React {
  function lazy<T extends ComponentType<any>>(
    factory: () => Promise<{ default: T }>,
  ): T;

Explanation: Original React.lazy declaration looks like this:

function lazy<T extends ComponentType<any>>(
  factory: () => Promise<{ default: T }>
): LazyExoticComponent<T>;

It returns LazyExoticComponent type, which is superset of ExoticComponent. Unfortunately, this interface is written in way which don't support generics. However, according to comment above the interface, it is meant only for internal distinction between "regular" and other components, like results of lazy and memo calls; in JSX syntax there's no difference between this ExoticComponent and Component. That's why we can safely omit LaxyExoticComponent type in our custom override and make use of generics.

Related Query

More Query from same tag