typescript 根据推断的类型使可选参数成为必需参数

qxsslcnc  于 2023-02-17  发布在  TypeScript
关注(0)|答案(1)|浏览(129)

我有一个存储键和回调函数的对象。这些回调函数可以有1个参数,也可以没有参数(未定义)。
最小示例:

const foo = {
  a: (arg: string) => null,
  b: () => null,
}

type keys = keyof typeof foo
type FirstArgument<Key extends keys> = Parameters<(typeof foo)[Key]>[0]

function testing<T extends keys>(key: T, arg?: FirstArgument<T>) {
  foo[key](arg)
}

testing('a', 'bar') // No error => correct
testing('a', 5) // Error => correct
testing('b') // No error > correct
testing('b', 'baz') // Error => correct, 'baz' is not assignable to type undefined

testing('a') // No error, even though FirstArgument<T> is string

我知道可选参数的| undefined部分使得这是完全可以预料到的结果。但是有什么方法可以实现我所寻找的结果吗?我尝试过重载函数和扩展参数,但两者都没有改变行为。

wsxa1bj1

wsxa1bj11#

您可以使用带有conditionaltuple类型的rest参数来创建所需的函数签名:
TSPlayground

const foo = {
  a: (arg: string) => null,
  b: () => null,
};

type Foo = typeof foo;
type FirstParam<K extends keyof Foo> = Parameters<Foo[K]>[0];

function testing<K extends keyof Foo>(
  key: K,
  ...args: FirstParam<K> extends undefined ? [] : [arg: FirstParam<K>]
): void {
  foo[key](args[0]!);
}

testing("a", "bar"); // ok
testing("b"); // ok

testing("a"); /* Error (expected)
        ~~~
Expected 2 arguments, but got 1.(2554) */

testing("a", 5); /* Error (expected)
             ~
Argument of type 'number' is not assignable to parameter of type 'string'.(2345) */

testing("b", "baz"); /* Error (expected)
             ~~~~~
Expected 1 arguments, but got 2.(2554) */

相关问题