redux ts(typescrip) reducer中action的类型检查

408 阅读2分钟

本人在写reducer中的action类的时候发现一些问题。为啥我的类型检查没有,过不了。后面实现了改功能,特在此记一笔。好记性不如烂笔头。

效果

在这里插入图片描述

我们就是要实现一个类似上图的效果,在每一个type中,action的类型是不一样。实现方式看下面的成功案例

成功案例

实现的业务场景,我想实现一个用户管理的功能,可以新增用户,删除,修改用户等。
每一个功能都是独立的并且所需要的参数是不一样的,所以做了以下类型检查。

公共类型

// common.ts // 公共类型
// 枚举每一个type类型。我是使用的枚举类型
export enum EUserListActionTypes {
  'add' = 'add',
  'del' = 'del',
  'upa' = 'upa',
  'setMore' = 'setMore'
}

/**
 * 每一个用户的对象类型
 */
export interface IUserObj {
  id: string,
  name: string,
  age?: number
}
/**
 * 修改用户的类型,id必选,其他的参数可选
 */
export type updateUser = { id: string } & Partial<IUserObj>

/**
 * 整个state的类型,里面包含一个用户列表
 */
export type userList = {
  userList: IUserObj[]
}

/**
 * 公共的action类型,一个泛型,必须包含两个属性,一个type,一个payload
 */
interface Action<T extends string, P> {
  type: T,
  payload: P
}
// 新增用户的action传值函数的返回值
export type addAction = Action<EUserListActionTypes.add, IUserObj>

// 修改用户的action传值函数的返回值
export type upaAction =  Action<EUserListActionTypes.upa, updateUser>

// 删除用户的action传值函数的返回值
export type delAction =  Action<EUserListActionTypes.del, Extract<{ id: string },updateUser> >

// 设置用户列表的action传值函数的返回值
export type setMoreAction = Action<EUserListActionTypes.setMore, IUserObj[]>

// 对于reducer的action的联合类型
export type ActionType = addAction | upaAction | delAction | setMoreAction

action

类型写好了了后,写action创造函数。如下:

import { addAction, delAction, EUserListActionTypes, IUserObj, setMoreAction, upaAction, updateUser, userList } from "../types/common";

/**
 * create an add userList action
 * @param payload 
 * @returns 
 */
export const createAddUserList = (payload: IUserObj): addAction => ({
  type: EUserListActionTypes.add,
  payload
})

/**
 * create a update userList action
 * @param payload 
 * @returns 
 */
export const createUpdateUserList = (payload: updateUser): upaAction => ({
  type: EUserListActionTypes.upa,
  payload
})


/**
 * create a delete userList action by id
 * @param payload 
 * @returns 
 */
export const createDelUserList = (payload: { id: string }): delAction => ({
  type: EUserListActionTypes.del,
  payload
})

/**
 * set more data in userList
 * @param payload 
 * @returns 
 */
export const createSetMoreUserList = (payload: IUserObj[]): setMoreAction => ({
  type: EUserListActionTypes.setMore,
  payload
})

最后写reducer

import { ActionType, EUserListActionTypes, userList } from "../types/common"

const initialState: userList = {
  userList: [
    { id: '1', name: 'cll', age: 12 },
    { id: '2', name: 'twinkle', age: 13 },
  ]
}
/**
 * userList reducer
 */
export default (state: userList = initialState, action: ActionType) => {
  switch (action.type) {
    case EUserListActionTypes.add:
      return ({ userList: [...state.userList, action.payload] })
    case EUserListActionTypes.upa:
      return state.userList.map(p => p.id === action.payload.id ? { ...p, ...action.payload } : p)
    case EUserListActionTypes.del:
      return state.userList.filter(f => f.id !== action.payload.id)
    case EUserListActionTypes.setMore:
      return ({ userList: [...state.userList, ...action.payload] })
    default:
      return state
  }
}