在Typescript中检查一个字符串是否是一种类型的键

6

我有一个状态类型,以及一个消息处理程序对象(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]) 是可行的(如果我忽略TypeScript的错误提示), 但TypeScript会有如下投诉:

表达式类型为“string”的元素隐含具有“any”类型,因为在类型“{ startRequestCounter: number; startResponseCounter: number; stopRequestCounter: number; stopResponseCounter: number; cuvettesCount: number; pipettesCount: number; robotMode: RobotMode; }”上不能使用字符串索引。

经过一番搜索,我发现keyof可能是我要找的,但是当我输入它时,却找不到keyof的定义。

2个回答

3
托德的回答不错,但我找到了一个更加简洁的答案,如下所示:
else if (key in getState().data)

1
我试图像这样进行检查: 在使用obj[key]之前,检查if (obj[key]),您的解决方案在这种情况下有效。 - BobtheMagicMoose

3

这是因为键(key)不能保证是在你的 DataState 中列出的键之一。

你可以使用 keyof 告诉 TypeScript 它将使用哪个键。

if (getState().data[key]) { 
    // Error Here
}
if (getState().data[key as keyof DataState]) {  
    // Not Here
}

这是否意味着我可以说 if (key is keyof DataState) - Jonathan Tuzman
不,你不能这样做。as只是一种告诉TypeScript你想假设变量是这种类型的方式,即使你无法证明它。当它被编译回JavaScript时,它会被移除,因为它实际上并没有做任何事情。 - Todd Skelton
你可以创建一个TypeGuard来实现这个功能,但你仍然需要在该方法中编写相同的逻辑。https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types - Todd Skelton
1
你必须意识到,Typescript类型实际上并不存在。它们只是帮助你编写代码的工具。因此,你不能根据某个东西是否是“类型”来执行任何操作。 - Todd Skelton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接