【问题标题】:Function that takes a predicate function (returning a boolean), and returns a predicate function with the same parameters [duplicate]接受谓词函数(返回布尔值)并返回具有相同参数的谓词函数的函数[重复]
【发布时间】:2015-09-04 04:58:24
【问题描述】:

所以,我想创建一个negate 函数,它接受一些函数,该函数为某些参数列表返回一个布尔值,并返回一个接受相同参数并产生完全相反的布尔值结果的函数。

如果我们把类型安全放在一边,这是可能的:

function negate(predicate: Function): Function {
    return function () {
        return !predicate.apply(this, arguments);
    }
}

我们甚至可以通过使用() => boolean 作为返回类型来指示结果函数返回一个布尔值。但是这个签名表明返回的函数没有参数——实际上,它应该得到与传入的predicate函数完全相同的参数。

我想要的是能够指定这一点。如果我将predicate 限制为一个参数,我可以:

function negate<A>(predicate: (a: A) => boolean): (a: A) => boolean {
    return function (a: A) {
        return !predicate.apply(this, arguments);
    }
}

我可以使用重载来为零、一、二等参数指定这个,方法是手动定义每个版本。在某个时候,我将能够接受任何函数应该合理采用的尽可能多的参数。如果我对“合理”的定义扩展,使用更多参数扩展它并不是非常很多工作。

另外,this answer 提出了不同的策略:

export function negate<Predicate extends Function>(p: Predicate): Predicate {
    return <any> function () {
        !p.apply(this, arguments);
    }
}

只要谓词确实返回布尔值,它就是类型安全的,但无法将参数限制为返回布尔值的东西(更糟糕的是,这会默默地转换任何非布尔值结果你得到一个布尔值以应用!,这不会在返回的函数的签名中指出)。

所以我真正想要的是既完全类型安全干燥。

Typescript 是否有任何功能可以实现这一点?

【问题讨论】:

  • @basarat 虽然类似,但我不认为这是一个重复问题,因为这里要求传入的函数返回boolean。编辑标题以专注于此。

标签: generics typescript variadic


【解决方案1】:

想出了一个办法。

interface IPredicate {
    (...args: any[]): boolean;
}
function negate<Predicate extends IPredicate>(p: Predicate): Predicate {
    return <any> function (): boolean {
        return !p.apply(this, arguments);
    }
}

IPredicate 接口允许我们定义无论我们采用什么参数,我们都期望一个布尔结果,然后使用 &lt;Predicate extends IPredicate&gt; 允许我们定义参数 p 和返回的函数将采用相同的参数,因为它们必须是 相同 Predicateextends IPredicate

negate 函数内部,我们使用apply,因此类型信息丢失。因此&lt;any&gt; 用于基本保证 TypeScript 编译器内部函数是正确的。这使得内部不是类型安全的,但它很小并且一旦编写就不需要维护。

这也可以扩展为处理谓词上的其他逻辑函数,例如union:

export function union<Predicate extends IPredicate>(
    p: Predicate,
    ...rest: Predicate[]
): Predicate {
    if (rest.length > 0) {
        return <any> function () {
            return p.apply(this, arguments) || union.apply(this, rest).apply(this, arguments);
        }
    }
    else {
        return p;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多