我该如何修复 "Cannot invoke an object which is possibly 'undefined'" 错误?
How do i fix "Cannot invoke an object which is possibly 'undefined'" error?
我在 Typescript 中使用 CreateContext,我明白为什么代码有问题,但我不知道如何解决它。它是类型安全 TX 的基本用法,使状态和 (useReducer) 分派在组件层次结构中可用
沙盒:
https://codesandbox.io/s/typescript-usereducer-todo-lk391?file=/src/App.tsx
上下文接口:
export interface ContextInterface {
state: AppState;
dispatch: (action: ActionType) => void;
}
使用 createContext 接口(我认为它必须是部分的,因为 createContext 不会采用零参数)
const TodoContext = createContext<Partial<ContextInterface>>({});
上下文已在我的父组件中初始化:
let [state, dispatch] = useReducer(reducer, initialState);
...
return (
<TodoContext.Provider value={{ state, dispatch }}>
...
当我使用上下文 TS 报告无法调用可能是 'undefined'.ts(2722) 的对象时,但是 console.log 按预期执行。
let { dispatch } = useContext(TodoContext);
console.log("dispatch", dispatch);
有没有办法正确定义Context对象并消除错误?
您可以将 useContext
调用包装在一个自定义挂钩中,该挂钩将处理类型问题:
- 首先更改
TodoContext
的定义以包含可选的空状态
const TodoContext = createContext<ContextInterface | undefined>(undefined);
- 创建一个自定义挂钩,抛出有关如何使用该挂钩的信息性错误
export const useTodoContext = (): ContextInterface => {
const context = useContext(TodoContext)
if (!context) {
throw Error('useTodoContext must be used inside TodoContext.Provider')
}
return context
}
那么你就可以毫无问题地使用这个钩子了。
此方法适用于所有类型的上下文数据。
从根本上说,问题是通过使用 Partial
,您已将上下文类型的所有属性设为可选,因此它们可能是 undefined
(从类型的角度来看),并且您需要如果你走那条路,允许这样做。
根据 createContext
documentation,默认情况下 仅在没有相关提供程序时使用 ,因此您可以不使用 Partial
,而只包含一个始终抛出的默认上下文对象:
const TodoContext = createContext<ContextInterface>({
state: {/*...mocked AppState stuff...*/},
dispatch: (action: ActionType) => {
throw new Error(`Default context used unexpectedly, check you have a provider`);
}
});
这样,TypeScript 就不会认为 dispatch
可能是 undefined
。
如果 AppState
属性没有任何合理的默认值,您可以使用 Proxy
在任何 属性 访问时抛出类似于上述错误的错误,因此尝试使用 context.state.x
会提供同样明显的错误。
我在 Typescript 中使用 CreateContext,我明白为什么代码有问题,但我不知道如何解决它。它是类型安全 TX 的基本用法,使状态和 (useReducer) 分派在组件层次结构中可用
沙盒: https://codesandbox.io/s/typescript-usereducer-todo-lk391?file=/src/App.tsx
上下文接口:
export interface ContextInterface {
state: AppState;
dispatch: (action: ActionType) => void;
}
使用 createContext 接口(我认为它必须是部分的,因为 createContext 不会采用零参数)
const TodoContext = createContext<Partial<ContextInterface>>({});
上下文已在我的父组件中初始化:
let [state, dispatch] = useReducer(reducer, initialState);
...
return (
<TodoContext.Provider value={{ state, dispatch }}>
...
当我使用上下文 TS 报告无法调用可能是 'undefined'.ts(2722) 的对象时,但是 console.log 按预期执行。
let { dispatch } = useContext(TodoContext);
console.log("dispatch", dispatch);
有没有办法正确定义Context对象并消除错误?
您可以将 useContext
调用包装在一个自定义挂钩中,该挂钩将处理类型问题:
- 首先更改
TodoContext
的定义以包含可选的空状态
const TodoContext = createContext<ContextInterface | undefined>(undefined);
- 创建一个自定义挂钩,抛出有关如何使用该挂钩的信息性错误
export const useTodoContext = (): ContextInterface => {
const context = useContext(TodoContext)
if (!context) {
throw Error('useTodoContext must be used inside TodoContext.Provider')
}
return context
}
那么你就可以毫无问题地使用这个钩子了。
此方法适用于所有类型的上下文数据。
从根本上说,问题是通过使用 Partial
,您已将上下文类型的所有属性设为可选,因此它们可能是 undefined
(从类型的角度来看),并且您需要如果你走那条路,允许这样做。
根据 createContext
documentation,默认情况下 仅在没有相关提供程序时使用 ,因此您可以不使用 Partial
,而只包含一个始终抛出的默认上下文对象:
const TodoContext = createContext<ContextInterface>({
state: {/*...mocked AppState stuff...*/},
dispatch: (action: ActionType) => {
throw new Error(`Default context used unexpectedly, check you have a provider`);
}
});
这样,TypeScript 就不会认为 dispatch
可能是 undefined
。
如果 AppState
属性没有任何合理的默认值,您可以使用 Proxy
在任何 属性 访问时抛出类似于上述错误的错误,因此尝试使用 context.state.x
会提供同样明显的错误。