采用谓词函数(返回布尔值)和 returns 具有相同参数的谓词函数的函数

Function that takes a predicate function (returning a boolean), and returns a predicate function with the same parameters

所以,我想创建一个 negate 函数,它采用一些函数,return 是一些参数列表的布尔值,return 是一个采用相同参数的函数并产生完全相反的布尔结果。

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

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

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

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

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

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

另外, 建议采用不同的策略:

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

只要 Predicate 实际上做 return 一个布尔值 就是类型安全的,但无法将参数限制为 return布尔值(更糟糕的是,这会默默地将您获得的任何非布尔值结果转换为布尔值,以便应用 ! 而这不会在 returned 函数的签名中指示)。

所以我真的很想完全类型安全 DRY。

Typescript 是否具有使这成为可能的任何功能?

想出办法了。

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

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

negate 函数内部,我们使用的是 apply,因此类型信息丢失了。因此 <any> 基本上用于向 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;
    }
}