Search code examples
angulartypescriptngrx

How do I dispatch two different properties to the selector?


I have a selector that is dependent on another one, which they need the userId to be able to "work".

But now I would like to create a selector that receives the "userId" and also receives another property called "userFriend".

What happens is that he is complaining about this parameter pass, as he is only finding one property, which is the "userId".

ERROR 1:

Property 'userFriend' does not exist on type '{ userId: any; }'

ERROR 2:

TS2339: Property 'userFriend' does not exist on type '{userId: any; } '.

34 (latestReadMessages, totalUnreadMessages, {userId, userFriend}) => {
                                                        ~~~~~~~~~~
src / app / services / store / chat / chat-selectors.service.ts: 34: 26 - error TS2769: No overload matches this call.
  Overload 1 of 8, '(mapFn: (state: object, props: {userId: any;}) => IChatFriendLatestMessageList, props ?: {userId: any;}): (source $: Observable <object>) => Observable <...> ', gave the following error.
    Argument of type '{userId: string; userFriend: IUser; } 'is not assignable to parameter of type' {userId: any; } '.
      Object literal may only specify known properties, and 'userFriend' does not exist in type '{userId: any; } '.
  Overload 2 of 8, '(key1: "user" | "chat", key2: "loading" | "data" | "dataError" | "ids" | "entities"): (source $: Observable <IStoreState>) = > Observable <any> ', gave the following error.
    Argument of type 'MemoizedSelectorWithProps <object, {userId: any; }, IChatFriendLatestMessageList, DefaultProjectorFn <IChatFriendLatestMessageList>> 'is not assignable to parameter of type' "user" | "chat" '.
      Type 'MemoizedSelectorWithProps <object, {userId: any; }, IChatFriendLatestMessageList, DefaultProjectorFn <IChatFriendLatestMessageList>> 'is not assignable to type' "chat" '.

34 return this.store.pipe (select (selector.getFriendLatestMessageList, {userId, userFriend}));
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~

SELECTORS:

export const messagesById = createSelector(selectAll, (chat: IChat[], { userId }) => {
  let messageIndex = 0;
  return chat.map((props, index) => {
    if (props.id === userId) {
      messageIndex = index;
      return props.messages;
    } else {
      return [];
    }
  })[messageIndex];
});

export const isLoading = createSelector(FEATURE_SELECTOR, ({ loading }) => loading);
export const error = createSelector(FEATURE_SELECTOR, ({ dataError }) => dataError);
export const friendMessages = createSelector(messagesById, messages => messages.filter(msg => !msg.isMain));
export const friendLatestMessage = createSelector(friendMessages, messages => messages[messages.length - 1]);
export const friendLatestReadMessages = createSelector(friendMessages, messages => messages.filter(msg => msg.isRead));
export const friendLatestUnreadMessages = createSelector(friendMessages, messages =>
  messages.filter(msg => !msg.isRead)
);
export const totalUnreadMessagesFriend = createSelector(friendLatestUnreadMessages, messages => messages.length);

export const getFriendLatestMessageList = createSelector(
  friendLatestMessage,
  totalUnreadMessagesFriend,

  (latestReadMessages, totalUnreadMessages, { userId, userFriend }) => {
    const latestMessageList: IChatFriendLatestMessageList = {
      user: userFriend.id,
      informations: {
        chatMessage: [latestReadMessages],
        isNewLastMessage: !userFriend.isClicked && totalUnreadMessages > 0,
        total: totalUnreadMessages,
      },
    };

    return latestMessageList;
  }
);

SERVICE FOR DISPATCH SELECTORS:

getFriendLatestMessageListById(userId: string, user: IUser): Observable<IChatFriendLatestMessageList> {
    return this.store.pipe(select(selector.getFriendLatestMessageList, { userId, user }));
}

INTERFACE:

export interface IChatFriendLatestMessageList {
    userFriend: IUser;
    informations: {
        chatMessage: IChatMessage[];
        isNewLastMessage: boolean;
        total: number;
    };
}

ERROR SCREENSHOT enter image description here


Solution

  • The problem is caused because this selector has own props and in the same time it uses parent selectors that also have own props.

    NGRX doesn't support it and to make it working we need to incapsulate the parent selectors.

    export const getFriendLatestMessageList = createSelector(
        s => s, // selecting the whole store.
        (store, { userId, userFriend }) => {
            // selecting our state.
            const latestReadMessages = friendLatestMessage(store, { userId });
            const totalUnreadMessages = totalUnreadMessagesFriend(store, { userId });
            // using them.
            const latestMessageList: IChatFriendLatestMessageList = {
                user: userFriend,
                informations: {
                    chatMessage: [latestReadMessages],
                    isNewLastMessage: !userFriend.isClicked && totalUnreadMessages > 0,
                    total: totalUnreadMessages,
                },
            };
    
            return latestMessageList;
        }
    );