Typescript 从同步或异步参数进行类型推断

Typescript 从同步或异步参数进行类型推断,typescript,asynchronous,promise,type-inference,Typescript,Asynchronous,Promise,Type Inference,我想定义一个“execute”方法,根据其参数返回同步或异步结果: type Callback = (...args: Arguments) => Result const result: Result = execute(callback: Callback, args: Arguments) type Callback=(…args:Arguments)=>Promise const result:Promise=execute(回调:回调,args:参数) type Callba

我想定义一个“execute”方法,根据其参数返回同步或异步结果:

type Callback = (...args: Arguments) => Result
const result: Result = execute(callback: Callback, args: Arguments)
type Callback=(…args:Arguments)=>Promise
const result:Promise=execute(回调:回调,args:参数)
type Callback=(…args:Arguments)=>Result | Promise
const result:Promise=execute(回调:回调,args:Promise

console.clear()
类型回调=
|((…args:Arguments)=>结果)
|((…args:Arguments)=>Promise)
const execute=(callback:callback,args:Arguments | Promise):typeof args扩展Promise?Promise:ReturnType=>{
if(args实例of Promise){
返回参数。然后(已解决参数=>{
常量结果=回调(…已解析参数)
返回结果
})
}
否则{
返回回调(…((参数???[])作为参数))
}
}
const async_demo=async(值:number)=>{
常数a=等待承诺。解决(1)
返回一个+值
}
const sync_demo=(值:number)=>1+值
类型SyncDemoResult=ReturnType
const result_1:number=execute(同步演示,[1])
const result_2:Promise=execute(sync_demo,Promise.resolve([1]作为[number]))
const result\u 3:Promise=execute(异步\u演示,[1])
const result\u 4:Promise=execute(异步\u演示,[1])

可能吗?

是的,可能。下面定义了两个重载:第一个接受直接回调参数,第二个-承诺解析回调参数:

type AnyFunc = (...args: any[]) => any;

function execute<T extends AnyFunc>(callback: T, args: Parameters<T>): ReturnType<T>
function execute<T extends AnyFunc>(callback: T, args: Promise<Parameters<T>>): Promise<ReturnType<T>>
function execute<T extends AnyFunc>(callback: T, args: Parameters<T> | Promise<Parameters<T>>) {
  if (args instanceof Promise) {
    return args.then(resolved_args => {
      const result = callback(...resolved_args)
      return result
    })
  }
  return callback(...args);
}
typeanyfunc=(…args:any[])=>any;
函数执行(回调:T,参数:Parameters):ReturnType
函数执行(回调:T,参数:Promise):Promise
函数执行(回调:T,参数:Parameters | Promise){
if(args实例of Promise){
返回参数。然后(已解决参数=>{
常量结果=回调(…已解析参数)
返回结果
})
}
返回回调(…args);
}

对于@aleksey-l的解决方案,我将使用此解决方案与异步或同步输入共享相同的代码:

typeanyfunc=(…args:any[])=>any;
键入AnyAsyncFunc=(…args:any[])=>Promise;
函数执行(回调:T,参数:Promise):Promise
函数执行(回调:T,参数:Parameters):ReturnType
函数执行(回调:T,参数:Promise):Promise
函数执行(回调:T,参数:Parameters | Promise){
if(args实例of Promise){
返回参数。然后(已解析的参数=>回调(…已解析的参数))
}
返回回调(…args);
}
// --------------------------------------------------
const async_demo=async(值:number)=>{
常数a=等待承诺。解决(1)
返回一个+值
}
// --------------------------------------------------
const sync_demo=(值:number)=>1+值
// --------------------------------------------------
const result_1:number=execute(同步演示,[1])
const result_2:Promise=execute(sync_demo,Promise.resolve([1]作为[number]))
const result\u 3:Promise=execute(异步\u演示,[1])
const result_4:Promise=execute(异步_演示,Promise.resolve([1]作为[number]))

我对TypeScript不太了解,不知道它是否可行,但即使可行,它是否也是可取的?有时是同步的,有时是异步的函数不是一个好主意,当然需要你破坏TypeScript中的类型安全性才能尝试它。我建议
executeAsync()
用于异步操作。使用此技术,我可以在客户端代码(同步)和服务器(异步)之间共享业务代码,其中数据访问(DDD中的存储库)是同步的或异步的,我可以得到在客户端同步,在服务器上异步的方法。承诺在性能上花费太多,有时在React应用程序中使用钩子会更复杂。但是,如果您的代码只是在API下面和API上面分支以处理异步和同步情况,而您只是通过非类型的我看不出你得到了什么。如果你按照同步和异步划分代码,你仍然可以共享同样多的代码。我认为你为了完美的代码共享而扭曲了API的设计和使用。依我看,这是错误的优先顺序。设计、使用和维护的清洁度功能编程带来了魔力:“执行”方法是货币化的,用于包装存储库访问:因此我可以创建在客户端(同步/存储)和服务器(异步/数据库)之间共享的业务方法.I注入存储库访问方法来构建客户端或服务器代码。相同的代码,2个签名取决于注入的方法。;-)非常感谢!我只是添加了一个case来完成所有我想做的事情
AnyAsyncFunc
是多余的,因为它已经被
AnyFunc
覆盖了,
ReturnType
将处理这个问题properly@aleksey-l:不,没有它,返回的类型是Promise;有没有办法用另一种方法来解决这个问题?你可以使用类似于
typeuncappromise=T扩展Promise的东西?R:T
type Callback = (...args: Arguments) => Result | Promise<Result>
const result: Promise<Result> = execute(callback: Callback, args: Promise<Arguments>)
console.clear()

type Callback<Arguments extends Array<any>, Result> =
| ((...args: Arguments) => Result)
| ((...args: Arguments) => Promise<Result>)

const execute = <Arguments extends Array<any>, Result> (callback: Callback<Arguments, Result>, args: Arguments | Promise<Arguments>): typeof args extends Promise<Arguments> ? Promise<Result> : ReturnType<typeof callback> => {
  if (args instanceof Promise) {
    return args.then(resolved_args => {
      const result = callback(...resolved_args)
      return result
    })
  }

  else {
    return callback(...((args ?? []) as Arguments))
  }
}

const async_demo = async (value: number) => {
  const a = await Promise.resolve(1)
  return a + value
}

const sync_demo = (value: number) => 1 + value
type SyncDemoResult = ReturnType<typeof sync_demo>

const result_1: number = execute(sync_demo, [1])
const result_2: Promise<number> = execute(sync_demo, Promise.resolve([1] as [number]))
const result_3: Promise<number> = execute(async_demo, [1])
const result_4: Promise<number> = execute(async_demo, [1])
type AnyFunc = (...args: any[]) => any;

function execute<T extends AnyFunc>(callback: T, args: Parameters<T>): ReturnType<T>
function execute<T extends AnyFunc>(callback: T, args: Promise<Parameters<T>>): Promise<ReturnType<T>>
function execute<T extends AnyFunc>(callback: T, args: Parameters<T> | Promise<Parameters<T>>) {
  if (args instanceof Promise) {
    return args.then(resolved_args => {
      const result = callback(...resolved_args)
      return result
    })
  }
  return callback(...args);
}