Typescript可选类型推断

Typescript可选类型推断,typescript,typescript-generics,Typescript,Typescript Generics,不确定这个问题是否正确,但我想让它推断出结果类型,但实际上不知道如何去做 下面是我现在的做法: type StateSetter=(prevState:S)=>S; 类型ResolvableHookState=S | StateSetter; 导出函数状态(状态:S):S; 导出函数resolveHookState(状态:StateSetter,currentState?:S):S; 导出函数resolveHookState(状态:ResolveableHookState,currentStat

不确定这个问题是否正确,但我想让它推断出结果类型,但实际上不知道如何去做

下面是我现在的做法:

type StateSetter=(prevState:S)=>S;
类型ResolvableHookState=S | StateSetter;
导出函数状态(状态:S):S;
导出函数resolveHookState(状态:StateSetter,currentState?:S):S;
导出函数resolveHookState(状态:ResolveableHookState,currentState?:S):S{
如果(状态类型===‘函数’){
返回(状态为StateSetter)(当前状态为S);
}
返回状态;
}
下面是我想如何使用它:

function someFunction(初始状态:ResolvableHookState=0){
const resolvedState=resolveHookState(initialState);
}
想法是让
resolveHookState(initialState)
返回数字类型,但出于明显的原因,它返回
ResolvableHookState

我试着通过推断来做到这一点,但它似乎并没有像我预期的那样起作用

type ResolvableHookStateType=S扩展状态设置器?T:S;
[UPD 1]
经过一番修补后,结果是:

导出类型StateSetter=(prevState?:S)=>S;
导出类型ResolvableHookState=S | StateSetter;
类型ResolvableHookStateType=S扩展ResolvableHookState?T:从来没有;
导出函数resolveHookState(状态:S):ResolveableHookStateType;
导出函数resolveHookState(状态:StateSetter,currentState?:S):ResolveableHookStateType;
导出函数resolveHookState(状态:ResolveableHookState,currentState?:S):ResolveableHookStateType{
如果(状态类型===‘函数’){
返回(状态为StateSetter)(currentState)作为ResolvableHookStateType;
}
返回状态为ResolvableHookStateType;
但我不确定这是解决这个问题的最优雅的方法。

接口可调用{
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>;
}
(…args:any[]):ReturnType; } 类型GenericReturnType=F扩展可调用 ?返回式 :从不; 函数someFunction(初始状态:ResolvableHookState=0){ const resolvedState=GenericReturnType; }

这篇文章可能会对您有所帮助。

如果您不介意将
保持在
的位置,那么这很有效

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
  }
}
导出类型StateSetter=(prevState?:S)=>S
导出类型ResolvableHookState=S | StateSetter
导出函数状态(
状态:可解析状态,
当前状态?:S
):S{
如果(状态类型===‘函数’){
返回(状态为StateSetter)(currentState)
}否则{
返回状态为S
}
}

这是我能得到的最接近的。需要记住的一点是,您的状态不能是
函数类型
,否则您将无法判断您正试图处理的重载

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);
类型状态=排除;
类型StateSetter=(prevState:S)=>S;
类型ResolvableHookState=状态|状态设置器;
函数状态(状态:state):S;
函数resolveHookState(stateSetter:stateSetter,currentState:State):S;
函数resolveHookState(状态或状态设置器:ResolveableHookState,currentState?:状态):S{
if(stateofStateSetter==='function'){
如果(当前状态!==未定义){
//From:StateSetter |(排除和函数)
//不确定为什么(排除和函数)不能解析为“从不”
const stateSetter=stateOrStateSetter作为stateSetter;
返回状态设置器(currentState);
}否则{
//如果使用stateSetter调用resolveHookState而不使用currentState
//基于方法签名,这是不可能的。
抛出新错误('Oops?');
}
}否则{
const state=stateOrStateSetter;
返回状态;
}
}
//与州政府通话
解析状态(0);
//还是和塞特一起
const stateSetter=(prevState:number)=>prevState+1;
解析状态(stateSetter,5);

基于@Grabofus解决方案,我自己制作:

导出类型StateSetter=(prevState:S)=>S;
导出类型InitialStateSetter=()=>S;
导出类型InitialHookState=S | InitialStateSetter;
导出类型HookState=S | StateSetter;
导出类型ResolvableHookState=S | StateSetter | InitialStateSetter;
导出函数resolveHookState(newState:S | InitialStateSetter):S;
导出函数resolveHookState(newState:Exclude,currentState:S):S;
导出函数resolveHookState(newState:StateSetter,currentState:S):S;
导出函数resolveHookState(newState:ResolveableHookState,currentState?:S):S{
if(typeof newState==='function'){
返回(函数为newState)(当前状态);
}
将newState返回为S;
}

小心使用
作为
关键字,它只是告诉TypeScript闭嘴:)如果我想在我的状态下存储函数会发生什么(这是第一个
作为
时忽略的),如果我使用状态设置器调用
resolveHookState
,而没有当前状态(第二个
作为
)?@Grabofus我正在制作custorm React钩子,该钩子应该作为其本机
useState
使用,它的参数可以是一个值或返回值的函数,如果它是一个函数,则调用它时不带参数,其结果用作状态。在这一部分中,它的作用与React完全相同(如果你想存储一个函数,你必须用另一个函数包装它)。@Grabofus此外,react的
useState
hook返回一个可以设置新状态的函数。它也可以是一个值或函数,但这次函数将接收一个参数-当前状态值。如果我是对的(我希望是%)我制作了一个涵盖两种用例的函数。此函数不会向用户公开,因此ivalid用例将被测试捕获。唯一的问题是,如果
是function类型(但不是StateSetter),您将调用它,而不是将其保存为状态。请查看下面的我的答案,看看它是否适合您的场景。:)编辑:删除了答案,似乎有一些问题。。如果您找不到解决方案,我将重新访问并很快更新它。非常感谢!基于您的解决方案,我已制作了一个完全适合我的解决方案