Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
527 views
in Technique[技术] by (71.8m points)

reactjs - How to use Multiple payload interface for reducer actions in redux typescript?

I have a reducer named Messages, that will have the following actions.

  1. GET_MESSAGES_START -> It Starts to Loads 10 Recent Message using API
  2. GET_MESSAGES_SUCCESS -> Completes loading 10 Recent Message using API
  3. GET_MESSAGES_FAIL -> API FAILURE
  4. RESET_MESSAGE -> Deletes a particular User's Messages/Inbox
  5. GET_SOCKET_MESSAGE -> Get's message from socket

GET_MESSAGE_START & RESET_MESSAGE -> Payload will have {chatUser: "username"}

GET_MESSAGE_SUCCESS -> Payload will have {chatUser: "username",nextPage: 2,count: 22,messages:Array<InboxMessages>}

GET_MESSAGE_FAIL -> Payload will have {error:[Error]}

GET_SOCKET_MESSAGE -> Payload will have {chatUser: "username", message: <InboxMessages> }

Interface


// For Reusing
export interface errorInterface{
    error?:null|string|Array<string>|{[key:string]:any}
}

// For Reusing
export interface BaseLoadingInterface {
    loading: boolean
}
// For Reusing
export interface NextPageInterface {
    nextPage: number | null
}

export interface InboxMessages {
    id: number,
    user: userInterface,
    receiver: userInterface,
    message: string,
    timestamp: Date,
    thread: number,
    attachment: any
}

export interface MessageInboxInterface extends BaseLoadingInterface, NextPageInterface{
    user: string,
    messages: Array<InboxMessages>,
    count: number,
}


export interface MessageStateInterface extends errorInterface{
    chatUser: string | null,
    inbox: Array<MessageInboxInterface>
}


export interface MessagePayload {
    chatUser: string,
    nextPage: null | number,
    count: number,
    messages: Array<InboxMessages>
}

export interface MessageStartInterface {
    type: typeof GET_MESSAGES_START | typeof RESET_MESSAGE,
    payload:{
        chatUser: string
    }
}

export interface MessageSuccessInterface{
    type: typeof GET_MESSAGES_SUCCESS,
    payload:MessagePayload
}

export interface MessageFailInterface {
    type: typeof GET_MESSAGES_FAIL,
    payload: errorInterface
}

export interface SocketMessageInterface{
    type: typeof GET_SOCKET_MESSAGE,
    payload: InboxMessages
}

export type MessageAction = MessageStartInterface | MessageSuccessInterface | SocketMessageInterface


Reducer


const defaultMessagesState:MessageStateInterface = {
    chatUser:null,
    error:null,
    inbox:[],
};


export const userChatMessageReducer = (state:MessageStateInterface=defaultMessagesState, action:MessageActionInterface) => {
    const{type,payload}=action;
    const chatUserInbox = state.inbox.filter(el => el.user === payload.chatUser);
    const inbox = state.inbox.filter(el => el.user !== payload.chatUser);
    switch (type) {
        case GET_MESSAGES_START:
            // Returns a updated User Inbox
            getMessageStartInbox(state, payload)
            return{
                ...state,
                chatUser:payload.chatUser,
                inbox: inbox
            };

        case GET_MESSAGES_SUCCESS:
            // Returns a updated Inbox with messages
            return {
                ...state,
                inbox: [...inbox,getInboxMessage(state, payload)]
            };

        case GET_SOCKET_MESSAGE:
            // Initiate New Message From Socket and returns new message
            return {
                ...state,
                inbox: [...inbox,newInboxObject(state, payload.message)]
            };
        case RESET_MESSAGE:
            // Delete chat user's message
            return {
                ...state,
                inbox:[...inbox]
            };
        case GET_MESSAGES_FAIL:
            return {
                ...state,
                error: payload.error
            };
        default:
            return state
    }
};

But I am getting errors, saying, chatUser, messages, message not in MessageActionInterface -> Payload type. Those are not a valid type for MessageActionInterface.payload

question from:https://stackoverflow.com/questions/65831284/how-to-use-multiple-payload-interface-for-reducer-actions-in-redux-typescript

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The reason that you are getting errors within the branches of your switch statement is due to a small technicality. When you destructure the action object outside of the switch statement, Typescript assigns a type to both type and payload. They now have their own types, so Typescript isn't considering the relationship between them. Each case of the switch refines the type definition for type but not for payload.

The solution is simple: don't desctructure the action object. Use switch (action.type) and replace refences to payload with action.payload.

There is one more potential issue which is accessing payload.chatUser outside of the switch to generate the inbox. It seems like not all action types have a chatUser property (should user in InboxMessages be chatUser?).

We can conditionally access chatUser using a guard 'chatUser' in action.payload to make sure that the property exists. If not, we return null and get an empty array for the inbox.

const chatUser = ( 'chatUser' in action.payload ) ? action.payload.chatUser : null;
const inbox = state.inbox.filter(el => el.user !== chatUser);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...