React-Redux中TypeScript中Reducer的类型错误

时间:2017-12-09 15:07:16

标签: javascript reactjs typescript redux

我在我的React-Redux应用程序中使用TypeScript。我遵循了TypeScript React Starter,但是,那里提到的例子没有任何具有一些参数/有效载荷的动作方法。

我有一个简单的要求 -

  

显示名称列表,单击按钮时会添加新名称。单击另一个按钮时,会添加2个名称。

应用index.tsx的入口点如下所示 -

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
import { createStore } from 'redux';
import { StoreState } from './types';
import { listUsers } from './reducers';
import { Provider } from 'react-redux';
import ListUsers from './containers/ListUsers';

const store = createStore<StoreState>(listUsers, {
  'users': [
    {
      'id': 0,
      'firstName': 'Aniyah',
      'lastName': 'Luettgen',
      'phone': '861-332-5113',
      'email': 'Danika.Ryan84@yahoo.com',
      'role': 'admin'
    },
    {
      'id': 1,
      'firstName': 'Alisa',
      'lastName': 'Pacocha',
      'phone': '085-056-3901',
      'email': 'Eusebio68@yahoo.com',
      'role': 'admin'
    }
  ]
});

ReactDOM.render(
  <Provider store={store}>
    <ListUsers/>
  </Provider>,
  document.getElementById('root') as HTMLElement
);
registerServiceWorker();

常量文件(constants/index.tsx)看起来像这样 -

export const LIST_USERS = 'LIST_USERS';
export type LIST_USERS = typeof LIST_USERS;

export const ADD_USER = 'ADD_USER';
export type ADD_USER = typeof ADD_USER;

export const ADD_USERS = 'ADD_USERS';
export type ADD_USERS = typeof ADD_USERS;

类型(types/index.tsx)是 -

export interface User {
  id: number;
  firstName: string;
  lastName: string;
  phone: string;
  email: string;
  role: string;
}

export interface StoreState {
  users: Array<User>;
}

export interface Action<T> {
  type: string;
  payload?: T;
}

我的组件(components/ListUsers.tsx)看起来像这样 -

import * as React from 'react';
import { DispatchProps, ListUsersProps } from '../containers/ListUsers';
import { User } from '../types';

interface ListState {
  counter: number;
}

class ListUsers extends React.Component<ListUsersProps & DispatchProps, ListState> {

  constructor(props: ListUsersProps & DispatchProps) {
    super(props);

    this.addUser = this.addUser.bind(this);
    this.addMultipleUser = this.addMultipleUser.bind(this);

    this.state = {
      counter: 0
    };
  }

  render() {
    return (
      <div>
        <button onClick={() => this.addUser()}>Add User</button>
        <button onClick={() => this.addMultipleUser()}>Add User</button>
        {this.props.users.map((user: User) => (
          <div key={user.id}>{user.firstName}</div>
        ))}
      </div>
    );
  }

  private addUser() {
    this.props.addUser({
      id: this.state.counter,
      firstName: 'abcd',
      lastName: 'efgh',
      email: 'abcd@gmail.com',
      phone: '1234567890',
      role: 'admin'
    });
    this.setState({
      ...this.state,
      counter: this.state.counter + 1
    });
  }

  private addMultipleUser() {
    this.props.addUsers([{
      id: this.state.counter,
      firstName: 'abcd',
      lastName: 'efgh',
      email: 'abcd@gmail.com',
      phone: '1234567890',
      role: 'admin'
    }, {
      id: this.state.counter,
      firstName: 'ijkl',
      lastName: 'mnop',
      email: 'ijkl@gmail.com',
      phone: '1234567890',
      role: 'admin'
    }]);
    this.setState({
      ...this.state,
      counter: this.state.counter + 2
    });
  }
}

export default ListUsers;

我的容器组件(containers/ListUsers.tsx)看起来像这样 -

import { connect, Dispatch } from 'react-redux';
import { Action, StoreState, User } from '../types';
import ListUsers from '../components/ListUsers';
import { addUser, addUsers } from '../actions';

export interface ListUsersProps {
  users: Array<User>;
}

export interface DispatchProps {
  addUser(user: User): Action<User>;
  addUsers(users: Array<User>): Action<Array<User>>;
}

export const mapStateToProps = (state: StoreState): ListUsersProps => {
  return {
    users: state.users
  };
};

export const mapDispatchToProps = (dispatch: Dispatch<DispatchProps>) => {
  return {
    addUser: (user: User) => dispatch(addUser(user)),
    addUsers: (users: Array<User>) => dispatch(addUsers(users))
  };
};

export default connect<ListUsersProps, DispatchProps, {}>(mapStateToProps, mapDispatchToProps)(ListUsers);

现在这里是我面临问题的减速器(reducers/index.tsx) -

import { Action, StoreState, User } from '../types';
import { ADD_USER, ADD_USERS, LIST_USERS } from '../constants';

export const listUsers = (state: StoreState, action: Action<User>): StoreState => {
  switch (action.type) {
    case LIST_USERS:
      return state;
    case ADD_USER:
      return {
        ...state,
        users: action.payload === undefined ? [...state.users] : [...state.users, action.payload]
      };
    case ADD_USERS:
      return {
        ...state,
        users: action.payload === undefined ? [...state.users] : [...state.users, ...action.payload]
      };
    default:
      return state;
  }
};

这里编译器在<{p>}中的reducers/index.tsx中说明了这一点

case ADD_USERS:
  return {
    ...state,
    users: action.payload === undefined ? [...state.users] : [...state.users, ...action.payload]
  };

action.payloadUser而非Array<User>是正确的(我已声明减速器的类型为(state: StoreState, action: Action<User>))。

我该如何使用它?如果没有替代方案,我将不得不为每个ACTION编写单独的缩减器,这些缩小器具有不同的payload,我认为这是不好的。

我使用DispatchProps类型的方式对我来说也很奇怪。我想针对mapStateToPropsmapDispatchToProps的类型关注this

有没有解决这个问题?

PS:我使用的是reactreduxreact-redux个库。

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。我不确定这是否是正确的方法。

而不是像这样制作动作类型泛型 -

interface Action<T> { 
  type: string;
  payload?: T;
}

我为每个Action创建了单独操作类型,然后Reducer接受的操作类型将是|

因此,类型看起来像这样(types/index.tsx) -

import { ADD_USER, ADD_USERS, LIST_USERS } from '../constants';

export interface User {
  id: number;
  firstName: string;
  lastName: string;
  phone: string;
  email: string;
  role: string;
}

export interface StoreState {
  users: Array<User>;
}

export type ListUsersAction = {type: typeof LIST_USERS};
export type AddUserAction = {type: typeof ADD_USER, payload: User};
export type AddUsersAction = {type: typeof ADD_USERS, payload: Array<User>};

export type Actions = ListUsersAction | AddUserAction | AddUsersAction;

和容器组件(containers/ListUsers.tsx)看起来像这样 -

import { connect, Dispatch } from 'react-redux';
import { AddUserAction, AddUsersAction, StoreState, User } from '../types';
import ListUsers from '../components/ListUsers';
import { addUser, addUsers } from '../actions';

export interface ListUsersProps {
  users: Array<User>;
}

export interface DispatchProps {
  addUser(user: User): AddUserAction;
  addUsers(users: Array<User>): AddUsersAction;
}

export const mapStateToProps = (state: StoreState): ListUsersProps => {
  return {
    users: state.users
  };
};

export const mapDispatchToProps = (dispatch: Dispatch<DispatchProps>) => {
  return {
    addUser: (user: User) => dispatch(addUser(user)),
    addUsers: (users: Array<User>) => dispatch(addUsers(users))
  };
};

export default connect<ListUsersProps, DispatchProps>(mapStateToProps, mapDispatchToProps)(ListUsers);

不再有编译错误,payloadADD_USER ADD_USERS已正确收到。

建议减少操作类型样板here