基于条件类型的可选参数

43

在TypeScript中,是否可以根据条件类型使函数具有强制或可选参数?

这是我目前的进展:

const foo = <T extends string | number>(
    first: T,
    second: T extends string ? boolean : undefined
) => undefined;

foo('foo', true); // ok, as intended
foo(2, true); // not ok, as intended
foo(2, undefined); // ok, as intended
foo(2); // compiler error! I want this to be ok

1
可选参数是一种运行时特性(评估和传递默认值),不能受类型系统的影响。 - SLaks
你可以使用一个简单的重载类型代替。 - SLaks
2个回答

82
您可以使用 3.1 版本中的 "Tuples in rest parameters and spread expressions" 来完成此操作。 详情请参考
const foo = <T extends string | number>(
  first: T, 
  ...a: (T extends string ? [boolean] : [undefined?])
) => undefined;

foo('foo', true); // ok, as intended
foo(2, true); // not ok, as intended
foo(2, undefined); // ok, as intended
foo(2); // ok

但更好的方法是使用重载。

function foo2(first: string, second: boolean) : undefined
function foo2(first: number, second?: undefined): undefined
function foo2<T>(first: T, second?: boolean): undefined{
  return undefined
}

foo2('foo', true); // ok, as intended
foo2(2, true); // not ok, as intended
foo2(2, undefined); // ok, as intended
foo2(2); // ok

11
如果你想完全删除参数,也可以使用 : [] 代替 : [undefined?] - ProdigySim
@ProdigySim,您描述的方式是否可以使用重载来实现? - Julien
需要注意的是,在使用本答案前半部分的解决方案时,a 参数被包装在一个数组中,这意味着您需要通过 a[0] 重新赋值或使用 ...a - Julien
你只需要在重载中省略参数。function foo2(first: number): undefined; - ProdigySim
2
有人能解释一下为什么我们需要将它包装成一个数组吗? - kidz55
显示剩余6条评论

3
为了确保不提供第二个参数(即使未定义),您可以将两个参数分组到rest语句中。
const bar = <T extends string | number>(
  ...args: (T extends string ? [T, boolean] : [T])
) => undefined;

// Usage

bar('bar', true); // ok, as intended
bar(2, true); // not ok, as intended
bar(2); // ok, as intended
bar(2, undefined); // not ok

这是对@titian-cernicova-dragomir答案的一个小补充。

演示


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接