[英]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.