所以,我想创建一个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是否有任何可以实现此功能的功能?
答案 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;
}
}