Я пытаюсь использовать response-redux с машинописным текстом и получаю сообщение об ошибке типа, когда пытаюсь ввести реквизиты с помощью 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 компонента на любой также решает проблему. Похоже, что система типов не понимает, что два объекта объединены двумя отображенными функциями.

11
Ochowie 3 Май 2016 в 20:05

2 ответа

Лучший ответ

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

8
Ochowie 4 Май 2016 в 04:14

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

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);
40
vinga 27 Окт 2016 в 08:47