上下文 Api、useReducer 和 Typescript - 组件上无法访问计算值

ContextApi, useReducer, & Typescript - calculated value is not accessible on component

抱歉标题有点含糊,但我很难在这里更精确。

所以我有一个 Context/Reducer 逻辑,我在其中使用一些值初始化上下文。然后,我在自定义提供程序上有一个缩减器逻辑,并使用 useMemo 来计算 values。当试图在组件上访问其中一个值(不在 state/initialState 中)时,打字稿对我很生气,并告诉我该值在 State 上不存在。补救此警告的最佳方法是什么?

我对 Context/Reducer.

的定义如下
interface State {
  displaySidebar: boolean
}

const initialState = {
  displaySidebar: false
}

type Action =
  | {
      type: 'OPEN_SIDEBAR'
    }
  | {
      type: 'CLOSE_SIDEBAR'
    }

const UIContext = React.createContext<State>(initialState)
UIContext.displayName = 'UIContext'

const uiReducer = (state: State, action: Action): State => {
  switch (action.type) {
    case 'OPEN_SIDEBAR': {
      return {
        ...state,
        displaySidebar: true,
      }
    }
    case 'CLOSE_SIDEBAR': {
      return {
        ...state,
        displaySidebar: false,
      }
    }
  }
}

const UIProvider: FC = (props) => {
  const [state, dispatch] = React.useReducer(uiReducer, initialState)
  const openSidebar = (): void => dispatch({ type: 'OPEN_SIDEBAR' })
  const closeSidebar = (): void => dispatch({ type: 'CLOSE_SIDEBAR' })
  const value = useMemo(
    () => ({
      ...state,
      openSidebar,
      closeSidebar,
    }),
    [state]
  )
  return <UIContext.Provider value={value} {...props} />
}

export const useUI = () => {
  const context = React.useContext(UIContext)
  if (context === undefined) {
    throw new Error(`useUI must be used within a UIProvider`)
  }
  return context
}

export const ManagedUIContext: FC = ({ children }) => (
  <UIProvider>
    <ThemeProvider>{children}</ThemeProvider>
  </UIProvider>
)

现在,当我尝试在组件打字稿中使用 const {closeSidebar} = useUI() 时,我很生气并告诉我 Property 'closeSidebar' does not exist on type 'State'. 我明白了,但我无法弄清楚如何正确添加 closeSidebarReact.Context 类型。

当您创建上下文时,您告诉 TS 它的类型将是 State,因此它不希望那里有任何其他内容。如果你想添加额外的字段,你可以创建一个交集类型,state + methods,或者只是 React.createContext<State & {openSidebar : ()=> void, closeSidebar: ()=> void}> 的命名类型。请注意,由于您的初始状态没有方法,您需要将它们设为可选或提供某种虚拟版本。