typescript 将回调参数反映到外部函数

sbdsn5lh  于 2023-03-04  发布在  TypeScript
关注(0)|答案(2)|浏览(234)

我创建了一个简单的模块,名为tryCatchWrap,它接受一个回调函数,并将其 Package 在一个try/catch块中。

type AsyncCb = (...args: any[]) => Promise<any>

export default function tryCatchWrap(cb: Function): AsyncCb {
  return async (...args: any[]) => {
    try {
      await cb(...args)
    } catch (err) {
      console.log((err as Error).message)
    }
  }
}

我有一个异步函数,我想尝试这个很酷的工具:

async function testFn(testStr: string) {
  // ... code
}

所以我把这个函数封装在tryCatchWrap方法中:

const testFn = tryCatchWrap(async function testFn(testStr: string) {
  // ... code
})

testFn()

现在我只剩下一个问题了。当我把鼠标悬停在testFn变量上时,我看不到testStr: string的调用签名,而是看到了外部函数的调用签名:...args: any[].
如何反映内部接口,以便在将鼠标悬停在变量testFn上时看到testStr: string而不是...args: any[]

dgiusagp

dgiusagp1#

您需要添加一些泛型类型参数来捕获实际的调用点参数类型:

export default function tryCatchWrap<A extends any[], R>(cb: (...a: A) => Promise<R>): (...a: A) => Promise<R | null> {
  return async (...args: A): Promise<R | null>  => {
    try {
      return await cb(...args)
    } catch (err) {
      console.log((err as Error).message)
      /// you could also decide on passing in a default value, or returning an error, or some other way to signal an error
      return null; 
    }
  }
}

const testFn = tryCatchWrap(async function testFn(testStr: string) {
  // ... code
  return 1;
})

let r = testFn("")

Playground链接
在上面的例子中,我返回了null以防止出错,你也可以做其他的事情,比如返回R | Error(ex)或者传入一个默认值作为出错的条件(ex)

mum43rcc

mum43rcc2#

如果你使用any,你基本上是在禁止对这部分代码进行类型检查,相反,你应该使用泛型,问题是泛型变量类型很难实现(也许可以查看this question来了解更多信息)这里我只是说你有一个参数,如果你想假装你有多个参数,你可以使用一个带字段的对象,所以你需要写testFn({ arg1: something, arg2: somethingElse })而不是testFn(something, somethingElse)
我能得到的最接近你想要的是:

type Callback<T, U> = (args: T) => U
type AsyncCb<T, U> = (args: T) => Promise<U>

export default function tryCatchWrap<T, U>(cb: Callback<T, Promise<U>>): AsyncCb<T, U | void> {
  return async (args: T) => {
    try {
      await cb(args)
    } catch (err) {
      console.log((err as Error).message)
    }
  }
}

const testFnVoid = tryCatchWrap(async function testFn(testStr: string) {
    // ...code
})

const testFnString = tryCatchWrap(async function testFn(testStr?) {
    return "It works!"
})
  
testFnVoid("lol") // Typescript says `const testFnVoid: (args: string) => Promise<void>`

testFnString(null) // Typescript says `const testFnString: (args: unknown) => Promise<string | void>`

另外,注意你必须Assert函数可以是void,因为当你捕捉到一个错误时,你不会返回一个值,所以你必须处理未定义的情况,以避免错误,如下所示:

const testFnString = tryCatchWrap(async function testFn(testStr?) {
    return { thisIs: "an example" }
})

async function consume() {
    const result = await testFnString(null)
    // result.thisIs <- typescript raises an error: "Property 'thisIs' does not exist on type 'void'."

    if (result != undefined) {
        console.log(result.thisIs) // This works
    }
}

相关问题