使用TypeScript与React-Redux时出现类型错误

12

我正在尝试在typescript中使用react-redux,并且当我尝试使用connect()和mapStateToProps注入props时出现类型错误。

我的组件看起来像这样:

function mapStateToProps(state) {
    return {
        counter: state.counter
    };
}

function mapDispatchToProps(dispatch) {
    return {
        incr: () => {
            dispatch({type: 'INCR', by: 2});
        },
        decr: () => {
            dispatch({type: 'INCR', by: -1});
        }
    };
}




export default class Counter extends React.Component<HelloProps, any> {
    render() {
        return (
          <div>
              <p>
                  <label>Counter: </label>
                  <b>#{this.props.counter}</b>
              </p>
              <button onClick={e => this.props.incr() }>INCREMENT</button>
              <span style={{ padding: "0 5px" }}/>
              <button onClick={e => this.props.decr() }>DECREMENT</button>
        );
    }
}


export default connect(mapStateToProps, mapDispatchToProps)(Counter);

店铺看起来像这样

let store = createStore(
    (state:HelloState, action:HelloAction) => {
        switch (action.type) {
            case 'INCR':
                return {counter: state.counter + action.by};
            default:
                return state;
        }
    },

最后,我已经定义了我的类型为:

interface HelloProps {
    counter?: number;
    incr?: () => any;
    decr?: () => any;
}

interface HelloState { 
    counter:number;
}

interface HelloAction { 
    type:string, 
    by:number;
}

当我尝试编译代码时,我收到了以下错误:

(39,61): error TS2345: Argument of type 'typeof Counter' is not assignable to parameter of type 'ComponentClass<{ counter: any; } & { incr: () => void; decr: () => void; }> | StatelessComponent<...'.
  Type 'typeof Counter' is not assignable to type 'StatelessComponent<{ counter: any; } & { incr: () => void; decr: () => void; }>'.
    Type 'typeof Counter' provides no match for the signature '(props?: { counter: any; } & { incr: () => void; decr: () => void; }, context?: any): ReactElement<any>' 

有趣的是尽管它抛出类型错误,但代码仍然可以工作。将组件的属性接口更改为任意类型也可以解决此问题。似乎类型系统无法理解这两个对象是由两个映射函数合并而成的。


你正在两次导出计数器组件,这可能也是一个问题。 - Hinrich
2个回答

40
为了保持类型安全,您可以将props分成几个部分,一个负责普通props,另一个负责dispatchers:

为了保持类型安全,您可以将props分成几个部分,一个负责普通props,另一个负责dispatchers:

import * as React from 'react';
import {connect}  from 'react-redux';

interface StateProps {
    textPros: string,
    optionalText?: string,

}
interface DispatchProps {
    onClick1: Function,

}

class MyComp extends React.Component<StateProps & DispatchProps , any> {
    render() {
         return (<div onClick={this.props.onClick1}>{this.props.textPros}</div>);
    }
}
const mapStateToProps = (state: any, ownProp? :any):StateProps  => ({
    textPros: "example text",
});
const mapDispatchToProps = (dispatch: any):DispatchProps => ({
    onClick1: () => {
        dispatch({ type: 'CLICK_ACTION'});
    }
});
export default connect(mapStateToProps, mapDispatchToProps)(MyComp);

对于那些寻求快速解决办法的人:只需在基础组件中添加 "as any"。

export default connect(mapStateToProps, mapDispatchToProps)(MyComp as any);

在我的情况下,我没有为 mapDispatchToProps 设置任何值,因此明确地传递 nullundefined 而不是省略该值似乎可以消除错误:export default connect(mapStateToProps, null)(MyComponent); - Shepmaster
as. as? as! \(^o^)/ - Raffael
这个具体的失败是因为你需要类型参数化连接:即使如此,似乎 connect 还存在更深层次的问题. - user2735832
使用TypeScript然后到处放any的意义在哪里?这是个糟糕的例子。 - Denis Frezzato

9

我在这个 Github issue 的倒数第二篇帖子中找到了答案。如果在 mapStateToProps 和/或 mapDispatchToPropsconnect 上没有类型参数,它将产生两个映射函数返回类型的交集。


你有没有关于这个问题找到更多的信息(解释)?我注意到你在Github问题上没有收到任何答案。你是否在使用return类型来为mapStateToProps和mapDispatchToProps定义返回值(就像你建议的那样,可能需要将接口成员设置为可选)?这是我目前正在应用的方法,以便能够运行。 - Jeroen
1
是的,我在mapStateToProps和mapDispatchToProps上指定了返回类型。无论如何,接口成员必须是可选的,否则在调用组件时会失败。我不是很喜欢TS与Redux和react-redux的connect方法的工作方式,但我现在想不到一个好的解决办法。 - Ochowie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接