【发布时间】:2020-11-12 05:36:10
【问题描述】:
当我在其他组件中使用状态时,TypeScript 似乎没有识别出属性state.recipes 确实存在,如果YummlyState 是RecipesState 的类型,就会出现这种情况。我怀疑YummlyState 始终是InitialState 的类型,因为这是它最初的类型,因为设置了初始状态。
此外,您还注意到关于此上下文的其他任何您认为应该不同的地方吗?
非常感谢!
import React, {
createContext,
Dispatch,
PropsWithChildren,
ReactElement,
Reducer,
useContext,
useReducer,
} from 'react'
// Recipe
export type Recipe = {
id: number
title: string
image: string
readyInMinutes: number
diets: string[]
pricePerServing: number
servings: number
}
// Response
export type SpoonacularResponse = {
number: number
offset: number
results: Recipe[]
totalResults: number
}
// Yummly State
type StatusUnion = 'resolved' | 'rejected' | 'idle' | 'pending'
type InitialState = {
status: StatusUnion
}
type SingleRecipeState = InitialState & {
recipe: Recipe
}
type RecipesState = InitialState & {
recipes: Recipe[]
}
type ErrorState = InitialState & {
error: unknown
}
type YummlyState = InitialState | SingleRecipeState | RecipesState | ErrorState
// Action Union Type for the reducer
type Action =
| { type: 'pending' }
| { type: 'singleRecipeResolved'; payload: Recipe }
| { type: 'recipesResolved'; payload: Recipe[] }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
| { type: 'rejected'; payload: unknown }
// The initial state
const initialState: YummlyState = {
status: 'idle',
}
// The Reducer
function yummlyReducer(state: YummlyState, action: Action): YummlyState {
switch (action.type) {
case 'pending':
return {
status: 'pending',
}
case 'singleRecipeResolved':
return {
...state,
status: 'resolved',
recipe: action.payload,
}
case 'recipesResolved':
return {
...state,
status: 'resolved',
recipes: action.payload,
}
case 'rejected':
return {
...state,
status: 'rejected',
error: action.payload,
}
default:
throw new Error('This should not happen :D')
}
}
type YummlyContextType = {
state: YummlyState
dispatch: Dispatch<Action>
}
const YummlyContext = createContext<YummlyContextType>({
state: initialState,
dispatch: () => {},
})
YummlyContext.displayName = 'YummlyContext'
// eslint-disable-next-line @typescript-eslint/ban-types
function YummlyProvider(props: PropsWithChildren<{}>): ReactElement {
const [state, dispatch] = useReducer<Reducer<YummlyState, Action>>(
yummlyReducer,
initialState
)
const value = { state, dispatch }
return <YummlyContext.Provider value={value} {...props} />
}
function useYummlyContext(): YummlyContextType {
const context = useContext(YummlyContext)
if (!context) {
throw new Error(`No provider for YummlyContext given`)
}
return context
}
export { YummlyProvider, useYummlyContext }
【问题讨论】:
-
由于上下文值是多个状态类型的并集,因此在访问仅存在于成功类型上的属性之前,您必须检查您的值是否为成功类型。
-
我会稍微不同地定义联合,以便您可以使用 status 的值来计算其余部分。继续阅读“受歧视的工会”。我可以留下一个答案。
-
@LindaPaiste 好的,感谢您的回答。我会阅读它,但非常感谢您的回答:D!再次感谢!
-
@LindaPaiste 你的意思是这样的typescriptlang.org/docs/handbook/…,prettier 似乎不喜欢第一个|,而且它似乎仍然不起作用:c
-
是的,文档页面正是我的意思。尽管在更仔细地查看了您的代码之后,可区分联合在这里并不完美,因为您有两种不同类型的
success响应。我刚刚给你留了一个冗长的答案。
标签: reactjs typescript