Skip to content

Generic React HOCs broken in 3.5.0-rc #31468

Closed
@coolkev

Description

@coolkev

TypeScript Version: typescript@3.5.0-dev.20190518

Search Terms:
hoc, Higher order type inference

Code

Here is the code from the example: https://devblogs.microsoft.com/typescript/announcing-typescript-3-5-rc/#higher-order-type-inference-from-generic-constructors

type ComponentClass<P> = new (props: P) => Component<P>;
declare class Component<P> {
    props: P;
    constructor(props: P);
}

declare function myHoc<P>(C: ComponentClass<P>): ComponentClass<P>;

type NestedProps<T> = { foo: number, stuff: T };

declare class GenericComponent<T> extends Component<NestedProps<T>> {
}

// type is 'new <T>(props: NestedProps<T>) => Component<NestedProps<T>>'
const GenericComponent2 = myHoc(GenericComponent);

Expected behavior:
Should work the same when using "React.Component/Class" instead of inline definitions.

declare function myHoc<P>(C: React.ComponentClass<P>): React.ComponentClass<P>;

type NestedProps<T> = { foo: number, stuff: T };

declare class GenericComponent<T> extends React.Component<NestedProps<T>> {
}

// type should be 'new <T>(props: NestedProps<T>) => React.Component<NestedProps<T>>'
// actual type is 'React.ComponentClass<NestedProps<unknown>, any>'
const GenericComponent2 = myHoc(GenericComponent);

Actual behavior:

The component returned from the HOC loses it's generic type parameter and instead uses unknown.

React.ComponentClass<NestedProps<unknown>, any>

I was able to narrow down the issue to the ComponentClass definition. Using the example type works, or using an simple interface works. But if the ComponentClass definition has any other properties this behavior appears.

// works
type ComponentClass<P> = new (props: P) => Component<P>;

// works
interface ComponentClass<P = {}> {
    new (props: P, context?: any): Component<P>;    
}

// does not work
interface ComponentClass<P = {}> {
    new (props: P, context?: any): Component<P>;
    displayName?: string;
}

Playground Link:

Related Issues:
#30650

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions