#typescript
#typescript
Вопрос:
У меня есть тип для моего состояния, а также объект обработчиков сообщений (thunks), который явно вводится как Record<string, (val: any) => AppThunk>
Я получаю входящие сообщения, которые являются объектами, и их ключи могут совпадать с ключами объекта обработчика сообщений, и в этом случае я хочу вызвать обработчик сообщений, или их ключи могут совпадать с ключами DataState
, и в этом случае я хочу просто отправить их через updateState
.
Приведенный ниже код работает нормально.
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 }))
}
})
}
Однако я чувствую, что else if
в конце можно было бы написать более кратко.
else if (getState().data[key])
работает (если я ts-игнорирую это), но TypeScript жалуется:
Элемент неявно имеет тип ‘any’, поскольку выражение типа ‘string’ не может использоваться для индексирования типа ‘{ startRequestCounter: number; startResponseCounter: number; stopRequestCounter: number; stopResponseCounter: number; cuvettesCount: number; pipettesCount: number; robotMode: RobotMode; }’.
Я провел небольшой поиск, и похоже, что это keyof
может быть то, что я ищу, но keyof
даже не может быть найдено при вводе.
Ответ №1:
Ответ Тодда хороший, но я выяснил, что он в основном такой же краткий, как я искал:
else if (key in getState().data)
Комментарии:
1. Я пытался выполнить проверку следующим образом:
if (obj[key])
перед использованиемobj[key]
, и ваше решение работает в этой ситуации.
Ответ №2:
Это потому, что key не гарантированно является одним из ключей, перечисленных в вашем DataState
.
Вы можете сообщить TypeScript, что он будет использовать keyof
.
if (getState().data[key]) {
// Error Here
}
if (getState().data[key as keyof DataState]) {
// Not Here
}
Комментарии:
1. Означает ли это, что я мог бы сказать
if (key is keyof DataState)
?2. Нет, вы не можете этого сделать.
as
это просто способ сообщить TypeScript, что вы хотите предположить, что переменная имеет этот тип, даже если вы не можете это доказать. Когда это компилируется обратно в JavaScript, оно удаляется, потому что на самом деле ничего не делает.3. Вы можете создать TypeGuard, который бы вроде как делал это, но вы все равно записываете ту же логику в этом методе. typescriptlang.org/docs/handbook /…
4. Вы должны понимать, что типы Typescript на самом деле не существуют. Они просто помогают вам кодировать. Следовательно, вы не можете ничего делать на основе того, является ли что-либо «типом».