采用谓词函数(返回布尔值)和 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
和返回的函数要采用相同的参数,因为它们必须 相同 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;
}
}
所以,我想创建一个 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
和返回的函数要采用相同的参数,因为它们必须 相同 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;
}
}