[英]Error in Types for the reducers in TypeScript in React-Redux
I am using TypeScript for my React-Redux app. 我正在为我的React-Redux应用程序使用TypeScript。 I have followed the TypeScript React Starter , however, the example mentioned there does not have any action methods that has some arguments/payload.
我遵循TypeScript React Starter ,但是,上面提到的示例没有任何带有某些参数/有效载荷的操作方法。
I have a simple requirement - 我有一个简单的要求-
Show a list of names and when a button is clicked a new name is added.
显示名称列表,并在单击按钮时添加新名称。 When another button is clicked 2 names are added.
单击另一个按钮时,将添加2个名称。
The entry point for the app index.tsx
looks like this - 应用
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();
The constants file ( constants/index.tsx
) looks like this - 常量文件(
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;
The types ( types/index.tsx
) are - 类型(
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;
}
My Component ( components/ListUsers.tsx
) looks like this - 我的组件(
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;
My container component ( containers/ListUsers.tsx
) looks like this - 我的容器组件(
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);
Now here is the reducer where I am facing issues ( reducers/index.tsx
) - 现在这是我面临问题的
reducers/index.tsx
( 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;
}
};
Here the compiler says that in the reducers/index.tsx
in 这里的编译器说在
reducers/index.tsx
中
case ADD_USERS:
return {
...state,
users: action.payload === undefined ? [...state.users] : [...state.users, ...action.payload]
};
that action.payload
is User
and not Array<User>
which is right (I have declared the reducer with type (state: StoreState, action: Action<User>)
). 该
action.payload
是User
而不是Array<User>
,这是正确的(我已将reducer声明为类型(state: StoreState, action: Action<User>)
)。
How do I work with this? 我该如何处理? If there isn't an alternative, I will have to write separate reducers for every
ACTION
that has a different payload
which I think is bad. 如果没有其他选择,我将不得不为每个具有不同
payload
ACTION
编写单独的reducer,我认为这是不好的。
The way I am using the DispatchProps
type also looks very odd to me. 我使用
DispatchProps
类型的方式在我看来也很奇怪。 I am trying to follow this for the types of mapStateToProps
and mapDispatchToProps
. 我试图按照此为各类
mapStateToProps
和mapDispatchToProps
。
Is there any work around for this? 有什么解决办法吗?
PS: I am using react
, redux
and react-redux
libraries. PS:我正在使用
react
, redux
和react-redux
库。
I found a solution for this. 我找到了解决方案。 I am not sure if it is right way to do this.
我不确定这样做是否正确。
Instead of making the Action Type generic like so - 与其像这样使动作类型通用,不如说是-
interface Action<T> {
type: string;
payload?: T;
}
I created a Separate Action Type for each Action
and then the Action Type accepted by the Reducer would be the |
我为每个
Action
创建了一个单独的动作类型 ,然后减速器接受的动作类型将为|
of them. 其中。
So, the types look like this ( types/index.tsx
) - 因此,类型看起来像这样(
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;
and the Container Component ( containers/ListUsers.tsx
) looks like this - 容器组件(
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);
There are no compilation errors any more, and payload
for both ADD_USER
and ADD_USERS
is received properly. 不再有编译错误,并且已正确接收
ADD_USER
和ADD_USERS
payload
。
There is a recommendation to reduce the Action Type boilerplate here . 还有就是要减少操作类型样板推荐这里 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.