Reputation: 1
I am encountering a problem with the typization of a reducer function that aims to update any given property of the userData stored in the slice. It takes an array with the key and a value, where the key should be of type TUserData, and the value - of the specified type for the respective key in TUserData.
Here is the reducer:
updateUserProp(state, action: { payload: [keyof TUserData, TUserData[keyof TUserData]]; type: string }) {
const [key, value] = action.payload;
state.userData![key] = value;
},
And here is the TUserData type
type TUserData = {
email: string;
uid: string;
username: string;
firstName: string;
lastName: string;
phoneNumber: string;
createdOn: string;
initials?: string;
status: EUserStatus;
profilePhoto?: string;
chats?: { [x: string]: EChatStatus };
messagesSent?: { [x: string]: boolean };
}
The error
Type 'string | { [x: string]: EChatStatus; } | { [x: string]: boolean; } | undefined' is not assignable to type 'string & EUserStatus & (WritableDraft<{ [x: string]: EChatStatus; }> | undefined) & (WritableDraft<{ [x: string]: boolean; }> | undefined)'. Type 'undefined' is not assignable to type 'string & EUserStatus & (WritableDraft<{ [x: string]: EChatStatus; }> | undefined) & (WritableDraft<{ [x: string]: boolean; }> | undefined)'.
is from this line of codea state.userData![key] = value;
EDIT
I resolved the error with this solution
function updateUserProp<K extends keyof TUserData>(
state: { userData?: TUserData },
action: {
payload: [K, TUserData[K]];
type: string;
},
) {
const [key, value] = action.payload;
state.userData![key] = value;
}
The function works fine on its own. But when used as a reducer, it allows a value of different type (as long as it's among the valid types for the entire object) to be assigned to the key.
dispatch(authActions.updateUserProp(["status", undefined]))
doesn't produce an error, but updateUserProp({}, { payload: ["status", undefined]})
(ran from the playground) does.
Upvotes: 0
Views: 52
Reputation: 33796
You can use a generic type parameter constrained by keyof TUserData
so that the compiler can infer the specific key as shown below:
function updateUserProp<K extends keyof TUserData>(
state: { userData?: TUserData },
action: {
payload: [K, TUserData[K]];
type: string;
},
) {
const [key, value] = action.payload;
state.userData![key] = value;
}
Upvotes: 0