不确定问题是否正确,但我希望它推断结果类型,但实际上不知道如何执行。
这是我现在的操作方式:
type StateSetter<S> = (prevState: S) => S;
type ResolvableHookState<S> = S | StateSetter<S>;
export function resolveHookState<S>(state: S): S;
export function resolveHookState<S>(state: StateSetter<S>, currentState?: S): S;
export function resolveHookState<S>(state: ResolvableHookState<S>, currentState?: S): S {
if (typeof state === 'function') {
return (state as StateSetter<S>)(currentState as S);
}
return state;
}
这是我要使用的方式:
function someFunction(initialState: ResolvableHookState<number> = 0){
const resolvedState = resolveHookState(initialState);
}
想法是使resolveHookState(initialState)
返回数字类型,但是出于显而易见的原因,它返回ResolvableHookState<number>
我试图通过推断来做到这一点,但它似乎没有按我预期的那样工作。
type ResolvableHookStateType<S extends ResolvableHookState<any>> = S extends StateSetter<infer T> ? T : S;
[UPD 1]
经过一番修补后,最终结果是:
export type StateSetter<S> = (prevState?: S) => S;
export type ResolvableHookState<S> = S | StateSetter<S>;
type ResolvableHookStateType<S> = S extends ResolvableHookState<infer T> ? T : never;
export function resolveHookState<S>(state: S): ResolvableHookStateType<S>;
export function resolveHookState<S>(state: StateSetter<S>, currentState?: S): ResolvableHookStateType<S>;
export function resolveHookState<S>(state: ResolvableHookState<S>, currentState?: S): ResolvableHookStateType<S> {
if (typeof state === 'function') {
return (state as StateSetter<S>)(currentState) as ResolvableHookStateType<S>;
}
return state as ResolvableHookStateType<S>;
但是我不确定这是解决问题的最优雅的方法。
答案 0 :(得分:0)
interface Callable<ReturnType> {
(...args: any[]): ReturnType;
}
type GenericReturnType<ReturnType, F> = F extends Callable<ReturnType>
? ReturnType
: never;
function someFunction(initialState: ResolvableHookState<number> = 0){
const resolvedState = GenericReturnType<number, typeof initialState>;
}
https://reacttraining.com/react-router文章可能会为您提供帮助。
答案 1 :(得分:0)
如果您可以保留as
,那么可以使用
export type StateSetter<S> = (prevState?: S) => S
export type ResolvableHookState<S> = S | StateSetter<S>
export function resolveHookState<S>(
state: ResolvableHookState<S>,
currentState?: S
): S {
if (typeof state === 'function') {
return (state as StateSetter<S>)(currentState)
} else {
return state as S
}
}
答案 2 :(得分:0)
这是我能得到的最接近的。要记住的一件事是您的状态不能为Function
类型,否则您将无法确定要处理的过载。
type State<S> = Exclude<S, Function>;
type StateSetter<S> = (prevState: S) => S;
type ResolvableHookState<S> = State<S> | StateSetter<S>;
function resolveHookState<S>(state: State<S>): S;
function resolveHookState<S>(stateSetter: StateSetter<State<S>>, currentState: State<S>): S;
function resolveHookState<S>(stateOrStateSetter: ResolvableHookState<S>, currentState?: State<S>): S {
if (typeof stateOrStateSetter === 'function') {
if (currentState !== undefined) {
// From: StateSetter<S> | (Exclude<S, Function> & Function)
// Not sure why (Exclude<S, Function> & Function) doesn't resolve to never
const stateSetter = stateOrStateSetter as StateSetter<S>;
return stateSetter(currentState);
} else {
// If you call resolveHookState with a stateSetter and no currentState
// This should not be possible based on the method signatures.
throw new Error('Oops?');
}
} else {
const state = stateOrStateSetter;
return state;
}
}
// Call with state
resolveHookState(0);
// Or with setter
const stateSetter = (prevState: number) => prevState + 1;
resolveHookState(stateSetter, 5);
答案 3 :(得分:0)
基于@Grabofus解决方案是我自己的:
export type StateSetter<S> = (prevState: S) => S;
export type InitialStateSetter<S> = () => S;
export type InitialHookState<S> = S | InitialStateSetter<S>;
export type HookState<S> = S | StateSetter<S>;
export type ResolvableHookState<S> = S | StateSetter<S> | InitialStateSetter<S>;
export function resolveHookState<S>(newState: S | InitialStateSetter<S>): S;
export function resolveHookState<S>(newState: Exclude<HookState<any>, StateSetter<any>>, currentState: S): S;
export function resolveHookState<S>(newState: StateSetter<S>, currentState: S): S;
export function resolveHookState<S>(newState: ResolvableHookState<S>, currentState?: S): S {
if (typeof newState === 'function') {
return (newState as Function)(currentState);
}
return newState as S;
}