从useReducer中学习查看源码类型声明(Typescipt)
-
如果设计一个
useReducer,应当确保哪些数据的类型安全?State:应当让状态保持类型一致Action:应当规范Action类型
-
学习
useReducer类型声明-
function useReducer<R extends Reducer<any, any>, I>( reducer: R, initializerArg: I & ReducerState<R>, initializer: (arg: I & ReducerState<R>) => ReducerState<R> ): [ReducerState<R>, Dispatch<ReducerAction<R>>]; -
可见参数
reducer的类型是Reducer<any, any>,并且返回的类型会被推断为ReducerState<R>。- 我们根据
api的设计可以合理地猜测:返回的tuple第一个参数必然是State的类型。 - 观察返回值类型定义,可以确定
ReducerState<R>的操作是根据R (extends Reducer<any, any>)返回了State的类型,这样可以保证返回类型的确定性。
- 我们根据
-
State的类型从哪里来?-
进一步进入
Reducer<any any>的声明-
type Reducer<S, A> = (prevState: S, action: A) => S; - 不难看出,
Reducer就是典型的Reducer函数的类型结构接收State(S)类型和Action(A)类型,返回State类型 - 同时,我们可以通过
ReturnType<Reducer<S, A>>来获取State的类型,这让useReducer获取State类型的时机下放到了Reducer函数的泛型中
-
-
再进入
ReducerState<R>来验证我们的猜想-
type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never; - 源码的实现并不是从
ReturnType中获取,而是直接获取了Reducer函数的state参数的类型State,殊途同归。
-
-
-
-
总结
useReducer的泛型是这样的:useReducer(reducer, initialState)中的reducer函数会预定义好自己的泛型(用于规范state和action的类型),useReducer会通过infer来获取reducer中state的类型,用来规范返回值的类型。