是否可以键入检查规范化参数?

时间:2018-08-09 13:18:38

标签: typescript

假设我具有以下功能签名:

function someFunction(arg1?: number, arg2?: string, arg3?: string|string[]) {}

每个参数都是可选的,因此应将其称为

someFunction(undefined, undefined, [''])

如果我想省略其中一些。

现在,使用Node-NormalizeArguments之类的库,我可以按以下方式包装此函数:

function wrappedFunction() {
  const normalizedArgs = args(arguments, [
    args.number(undefined), 
    args.string(undefined),
    args.oneOf([
      args.array,
      args.string
    ], undefined)
  ]);
  return someFunction(...normalizedArgs)
}

,因此允许将其称为

someFunction([''])

获得相同的结果。

当然已经存在一些缺陷(我通过使用args.array丢失了string[]类型检查),但是这些缺陷可以在库代码中得到解决。真正的问题是:

如何定义此新包装函数的类型? (最好不要详细列出所有可能的参数组合,或者至少不要手工完成)

1 个答案:

答案 0 :(得分:2)

您可以使用一堆类型别名来生成带有所有参数子集的一组重载签名:

// `CAaOb`: first `a` parameters are already assigned, remaining `b` are
// optional.  `X` is the union of the types of the optional parameters following
// the last assigned parameter that are assumed to have already been skipped,
// meaning that the runtime type of the next argument must not belong to `X`.

type CA0O0<X, R> = () => R;

type CA1O0<A1, X, R> = (a1: A1) => R;
type CA0O1<X, O1, R> = CA1O0<Exclude<O1, X>, never, R> & CA0O0<X | O1, R>;

type CA2O0<A1, A2, X, R> = (a1: A1, a2: A2) => R;
type CA1O1<A1, X, O1, R> = CA2O0<A1, Exclude<O1, X>, never, R> & CA1O0<A1, X | O1, R>;
type CA0O2<X, O1, O2, R> = CA1O1<Exclude<O1, X>, never, O2, R> & CA0O1<X | O1, O2, R>;

type CA3O0<A1, A2, A3, X, R> = (a1: A1, a2: A2, a3: A3) => R;
type CA2O1<A1, A2, X, O1, R> = CA3O0<A1, A2, Exclude<O1, X>, never, R> & CA2O0<A1, A2, X | O1, R>;
type CA1O2<A1, X, O1, O2, R> = CA2O1<A1, Exclude<O1, X>, never, O2, R> & CA1O1<A1, X | O1, O2, R>;
type CA0O3<X, O1, O2, O3, R> = CA1O2<Exclude<O1, X>, never, O2, O3, R> & CA0O2<X | O1, O2, O3, R>;

function someFunction(arg1?: number, arg2?: string, arg3?: string|string[]) { }

const wrappedFunction: CA0O3<never, number, string, string | string[], void> = function() { 
  const normalizedArgs = args(arguments, [
    args.number(undefined), 
    args.string(undefined),
    args.oneOf([
      args.array,
      args.string
    ], undefined)
  ]);
  return someFunction(...normalizedArgs);
};

当然,您会丢失参数名称。如果要保留它们,则必须编写脚本来生成过载签名。