获取谓词函数(返回布尔值)并返回具有相同参数的谓词函数的函数

时间:2015-08-17 18:35:17

标签: generics typescript variadic

所以,我想创建一个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);
    }
}

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

所以我真的希望完全类型安全 DRY。

Typescript是否有任何可以实现此功能的功能?

1 个答案:

答案 0 :(得分:3)

想出办法。

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和返回的函数是采用相同的参数,因为它们必须都是{em>相同 Predicate extends 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;
    }
}