Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redux connect fails with unable to resolve signature of class decorator when called as an expression #9365

Closed
mythz opened this issue Jun 26, 2016 · 9 comments
Labels
Needs More Info The issue still hasn't been fully clarified

Comments

@mythz
Copy link

mythz commented Jun 26, 2016

TypeScript Version:

1.8.9

Not sure if this a TypeScript or Redux TypeScript definition issue but the behavior is unexpected. I'd like to use Redux connect() as a decorator which works fine when a React Component only has a single render() method, e.g:

import { connect } from 'react-redux';

@connect(
    (state) => ({ text: state.text })
)
class MyComponent extends React.Component<any, any> {
    render() {
        const shout = (txt) => txt.toUpper();
        return <div>{shout(this.props.text)}</div>;
    }
}

But it fails as soon as I add another method to the class, e.g:

import { connect } from 'react-redux';

@connect(
    (state) => ({ text: state.text })
)
class MyComponent extends React.Component<any, any> {
    shout(txt) {
        return txt.toUpper();
    }
    render() {
        return <div>{this.shout(this.props.text)}</div>;
    }
}

Which fails with:

Unable to resolve signature of class decorator when called as an expression.
Type 'ComponentClass<{}>' is not assignable to type 'void'.

I don't understand how adding a method to a class changes the structure of a class to cause this error?

After some trial and error I'm able to workaround this by creating a constructor function that removes the type declarations from connect's constructor function:

import { connect } from 'react-redux';

function reduxify(mapStateToProps, mapDispatchToProps?, mergeProps?, options?) {
    return target => (connect(mapStateToProps, mapDispatchToProps, mergeProps, options)(target) as any);
}

Which now lets me use the decorator as expected:

@reduxify(
    (state) => ({ text: state.text })
)
class MyComponent extends React.Component<any, any> {
    shout(txt) {
        return txt.toUpper();
    }
    render() {
        return <div>{this.shout(this.props.text)}</div>;
    }
}

But I'd prefer to be able to use react-redux native @connect() if possible. Is there anyway to resolve this issue without using a wrapper method?

@CarsonF
Copy link

CarsonF commented Jun 27, 2016

I think this as my problem #9357.

I think it may have to do with the decorator having a different return type. Maybe #4881 is the solution...

@mhegazy
Copy link
Contributor

mhegazy commented Jun 27, 2016

I am using the latest react-redux definition from definitely typed, (https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/react-redux/react-redux-2.1.2.d.ts), and i am unable to get a repro for this issue. can you provide more context?

@mhegazy
Copy link
Contributor

mhegazy commented Jun 27, 2016

I am using typescript@next.

@mhegazy mhegazy added the Needs More Info The issue still hasn't been fully clarified label Jun 27, 2016
@CarsonF
Copy link

CarsonF commented Jun 27, 2016

I think the error is coming from:

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;

If connect() says it returns a different type than the one passed in, TFunction, then void is tried next and fails. Hence the error.

@mythz
Copy link
Author

mythz commented Jun 27, 2016

The react-redux-2.1.2.d.ts is not the one I'm getting, which I installed with:

 typings install --save --ambient react-redux

Which is registered in typings.json as:

"react-redux": "registry:dt/react-redux#4.4.0+20160501125835",

Where connect() definition looks like:

export function connect(): InferableComponentDecorator;

export function connect<TStateProps, TDispatchProps, TOwnProps>(
mapStateToProps: MapStateToProps<TStateProps, TOwnProps>,
mapDispatchToProps?: MapDispatchToPropsFunction<TDispatchProps, TOwnProps>|MapDispatchToPropsObject
): ComponentDecorator<TStateProps & TDispatchProps, TOwnProps>;

export function connect<TStateProps, TDispatchProps, TOwnProps>(
mapStateToProps: MapStateToProps<TStateProps, TOwnProps>,
mapDispatchToProps: MapDispatchToPropsFunction<TDispatchProps, TOwnProps>|MapDispatchToPropsObject,
mergeProps: MergeProps<TStateProps, TDispatchProps, TOwnProps>,
options?: Options
): ComponentDecorator<TStateProps & TDispatchProps, TOwnProps>;

TypeScript Type definition management is a broken mess, hoping TS v2.0 resolves a lot of the issues with it. It's a constant battle trying to use popular libraries like React/Redux which are frequently broken.

@mythz
Copy link
Author

mythz commented Jun 27, 2016

So there's 2 versions of react-redux: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/react-redux

But react-redux.d.ts was updated 2 months ago and react-redux-2.1.2.d.ts was updated 4 months ago, so I'm assuming react-redux.d.ts is the latest version which is also what typings installs.

@CarsonF
Copy link

CarsonF commented Jun 30, 2016

Info here as well: DefinitelyTyped/DefinitelyTyped#8787

@seansfkelley
Copy link

Thanks for the link @CarsonF; I filed DefinitelyTyped/DefinitelyTyped#9951 to track this issue centrally. Perhaps this issue should be closed in favor of that one and #4881?

@alex-bel
Copy link

Here is a simplified code showing the issue:

declare class Base {
    constructor();
}

interface BaseClass {
    new(): Base;
}

declare function decorator(): (component: BaseClass) => BaseClass;

@decorator()
class TestClass extends Base {
  someMethod(): void {
  }
}

Both 1.8.10 and 2.0.0 fails to compile it with following error:

src/index.ts(11,1): error TS1238: Unable to resolve signature of class decorator when called as an expression.
Type 'BaseClass' is not assignable to type 'void'.

Configuration:

    "compilerOptions": {
        "outDir": "./dist/",
        "sourceMap": true,
        "noImplicitAny": true,
        "module": "commonjs",
        "target": "es5",
        "jsx": "react",
        "experimentalDecorators": true
    },

@mhegazy mhegazy closed this as completed Dec 29, 2016
@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Needs More Info The issue still hasn't been fully clarified
Projects
None yet
Development

No branches or pull requests

5 participants