Проверка, является ли строка ключом в типе, в Typescript

#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 на самом деле не существуют. Они просто помогают вам кодировать. Следовательно, вы не можете ничего делать на основе того, является ли что-либо «типом».