I have a type for my state, as well as an object of message handlers (thunks), which is explicitly typed as Record<string, (val: any) => AppThunk>
I get incoming messages that are objects, and their keys could match up with keys of the message handler object, in which case I want to call the message handler, OR their keys could match up with keys of the DataState, in which case I want to simply send them through to updateState.
The code below works fine.
type DataState = {
startRequestCounter: -1,
startResponseCounter: -1,
stopRequestCounter: -1,
stopResponseCounter: -1,
robotMode: RobotMode.Idle as RobotMode,
}
const messageHandlers: Record<string, (val: any) => AppThunk> = {
startRequestCounter: () => async (dispatch, getState) => // do stuff,
startResponseCounter: (counter: number) => dispatch => // do stuff,
stopResponseCounter: (counter: number) => dispatch => // do stuff
}
export const handleMessage = (message: MessagePayload): AppThunk => (dispatch, getState) => {
Object.entries(message).forEach(([snakeKey, value]) => {
const key = camelCase(snakeKey)
// call the message handler for this message, if there is one
if (messageHandlers[key]) {
dispatch(messageHandlers[key](value))
}
// if not, update the state if we have a state for this message
else if (Object.keys(getState().data).includes(key)) { // <~~~~ HERE!!!!
dispatch(updateState({ [key]: value }))
}
})
}
However, I feel like the else if at the end could be written more concisely.
else if (getState().data[key]) works (if I ts-ignore it), but TypeScript complains:
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ startRequestCounter: number; startResponseCounter: number; stopRequestCounter: number; stopResponseCounter: number; cuvettesCount: number; pipettesCount: number; robotMode: RobotMode; }'.
I've done a little searching, and it looks like keyof might be what I'm looking for, but keyof can't even be found when I type it.