如何从函数参数继承缩小类型?

How to inherit narrowed type from function argument?

我有一个函数接受另一个函数作为参数。参数是联合类型的函数,也可能有或没有参数。

type innerFn = () => void | (arg: string) => void | (arg: number) => void | (arg: {}) => void

function mainFn (innerFn: InnerFnType) {
   function run(arg?: *any*) {
      innerFn()
   }
   return run
}

我想知道运行参数是否可以基于传递给mainFn的函数被继承。

用例是:

const concreteInnerFn: InnerFnType = (arg: string) {
     do something
}

const run = mainFn(concreteInnerFn)

run("hello")  // OK
run(25) // ERROR
run({hello: true}) // ERROR

也就是说,如果我使用 (arg: string) => void 作为 innerFn,当我尝试使用 run() 时,它应该要求一个字符串类型的参数。

希望够清楚

你可以做到:

type InnerFn =
  | (() => void)
  | ((arg: string) => void)
  | ((arg: number) => void)
  | ((arg: Record<string, unknown>) => void)

const main = <
  Params extends Parameters<InnerFn>,
  >(fn: (...params: Params) => void) =>
  (...args: Params) => fn(...args)

/**
 * Ok
 */
const result0 = main(() => { }) // ok
result0() // ok
const result1 = main((a: string) => { })// ok
result1('hello') // ok
const result2 = main((a: number) => { }) // ok
result2(42) // ok
const result3 = main((a: { age: number }) => { }) // ok
result3({ age: 42 })

/**
 * Errors
 */
const result4 = main((a: Promise<number>) => { }) // expected error
const result5 = main((a: number[]) => { }) // expected error

Playground

说明

请不要使用 {} 作为类型,因为它是非常通用的类型。 javascript 和打字稿中的一切都是对象。因此 {} 不能用作约束。为此,最好使用 Record<string, unknown>

Parameters - returns 传递函数的所有参数的元组。

P.S。我希望你不介意我使用了箭头函数而不是 function。不是说更好,只是风格的问题