带可选参数的身份功能

时间:2019-06-14 18:58:14

标签: typescript typescript-generics

我们如何更改此标识函数以使其参数可选,以便在不带参数的情况下调用时返回未定义?

function f<T>(x: T): T {
    return x;
}

var a: number = f(1);
var b: null = f(null);
var c: undefined = f(undefined);

显而易见的方法没有通过strictNullChecks:

function f<T>(x?: T): T {
    return x; // TS2322
}

添加类型断言似乎可以解决问题……

function f<T>(x?: T): T {
    return x as T;
}

var d: undefined = f();

…但是实际上为错误代码在运行时失败打开了大门:

var e: number = f();
console.log(e.toExponential());

为type参数设置默认值无济于事:

function f<T = undefined>(x?: T): T {
    return x as T;
}

1 个答案:

答案 0 :(得分:3)

很难使编译器验证您的实现是安全的,所以我认为您在这里所做的最好的事情是可以确保调用者不会错误地调用它,但是在使用{{3 }}或“道德当量”以禁止实施中的警告。

最简单的方法是将f实现为type assertion

// call signatures
function f(): undefined;
function f<T>(x: T): T;
// impl signature
function f(x?: any) {
    return x;
}

在这里,您支持两个调用签名:一个零参数调用,其结果为undefined,并且没有泛型类型参数;或者一个单参数通用调用,其结果与输入相同。这应该完全符合您的预期:

var a = f(1); // number
var b = f(null); // null 
var c = f(undefined); // undefined
var d = f(); // undefined
var e: number = f(); // error! undefined is not number

重载函数就是我所说的与类型断言“在道德上等效的”东西,因为允许实现签名比任何调用签名都宽松。因此,您必须小心正确地实现该功能。

如果由于某些原因您不希望重载,则可以将overloaded functionconditional types一起使用,以创建一个通用函数,该函数接受零个或一个参数,并且其返回类型具体取决于的长度。参数列表:

function f<P extends readonly [any?]>(
  ...x: P
): P extends readonly [infer R] ? R : undefined {
  return x as any;
}

对于上面的示例ae,其行为方式相同。但是您仍在进行类型声明(在实现中为as any),它更加复杂且难看。我看到的唯一区别是,如果使用联合类型的参数传播来调用它,就像这样:

var hmm = f(...Math.random() < 0.5 ? ["hey"] : []) // different

适用于条件f,但不适用于超载的条件。我怀疑您是否需要它。

好的,希望能有所帮助;祝你好运!

rest tuples