[英]Extract return type and arguments types of a generic type
为了使它有意义,让我们看一下这个看起来像 react useReducer 的迷你天真的实现
type Reducer<S, A> = (prevState: S, action: A) => S;
type Dispatch<A> = (value: A) => void;
function useReducer<S, A>(reducer: Reducer<S, A>, initState: S): [getState: () => S, dispatcher: Dispatch<A>] {
let state = initState;
return [
() => state,
action => state = reducer(state, action)
];
}
// its working as expected (but that is not the question)
type CountActions =
| { type: "inc" }
| { type: "dec" }
| { type: "reset"; payload?: number };
const [getState, dispatch] = useReducer<number, CountActions>(
(state, action) => {
if (action.type === "inc") {
return state + 1;
}
if (action.type === "dec") {
return state - 1;
}
if (action.type === "reset") {
return action?.payload ?? 0;
}
return state;
},
0
)
getState()//0
dispatch({ type: 'inc' })
dispatch({ type: 'inc' })
getState()//2
dispatch({ type: 'dec' })
getState()//1
dispatch({ type: 'reset', payload: 2 })
getState()//2
dispatch({ type: 'reset' })
getState()//0
我的问题是:有没有办法编写 useReducer 的内部类型,只派生一个条目,即 Reducer 类型?
您将如何编写ExtractSFrom
和ExtractAFrom
?
// ideally I want to have something that is defined like the real thing ;)
function useReducer<R>(reducer: R, initState: ExtractSFrom<R>): [getState: () => ExtractSFrom<R>, dispatcher: (value: ExtractAFrom<A>) => void] {
let state = initState;
return [
() => state,
action => state = reducer(state, action)
];
}
提前致谢
这正是infer
关键字的用途。 如果检查实际useReducer
挂钩的类型,您会看到 React 正在推断State
的类型和来自 reducer function 的Action
。
type ReducerState<R extends Reducer<any, any>> = R extends Reducer<infer S, any> ? S : never;
type ReducerAction<R extends Reducer<any, any>> = R extends Reducer<any, infer A> ? A : never;
我们指定泛型R
必须是某种缩减器,又名R extends Reducer<any, any>
,然后向后工作以获取其泛型变量。
useReducer
钩子本身有几个不同的重载,但基本上它看起来像这样:
function useReducer<R extends Reducer<any, any>>(
reducer: R
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
其中泛型是 reducer State
和Action
的类型是从它派生的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.