Ошибка типа при использовании Typescript с React-Redux

Я пытаюсь использовать react-redux с typescript, и я получаю ошибку типа, когда пытаюсь ввести реквизит с помощью connect() и mapStateToProps.

мой компонент выглядит так:

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>' 

интересно, что код все еще работает, хотя его бросает типа ошибка. Кроме того, изменение интерфейса prop компонента на любой также решает проблему. Похоже, система типов не понимает, что два объекта объединены двумя сопоставленными функциями.

2 ответов


для сохранения безопасности типа вы можете разделить реквизит на части, один отвечает за нормальный реквизит и один для диспетчеров:

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);

для тех, кто ищет быстрый обходной путь: просто добавьте "как любой" в базовый компонент.

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

Я нашел ответ в предпоследнем посте на этом Github вопрос. Без параметра type на обоих mapStateToProps и/или mapDispatchToProps или connect это приведет к пересечению возвращаемых типов двух функций карты.