Predicate class implementation in TypeScript I am have created a predicate builder that takes predicates (functions with a single input and produce a boolean) and can chain them using boolean logic, so AND, OR and NOT. It is inspired by the Java Predicate class. This is mostly to practice my TypeScript, so general feedback is of course appreciated. However, I am interested in few points:


Naming. I don't like the Builder suffix here as it doesn't seem to fit. Although, I cannot exactly explain why it feels wrong. Partly, I'm used to builders producing an object as a result, not to be containers for the logic that will be later applied. This seems more of a Functor. Furthermore "predicate" is the mathematical and general term for a function of type (x: any) =&gt; boolean, so I don't want to name the class that way. Java gets away with it because it has functional interfaces.
Repetition. When using .and() and .or() the return is the same aside from the operator being used. This feels off. When I add a new method like .xor(), then on one hand, I don't want to repeat this. On the other, .xor() will not be implemented using a single operator. There should be a way to generalise the logic that I simply don't see.
Overloaded methods. Since you can't actually have method overloading in TypeScript/JavaScript you need to accept all possible signatures and sort out what to do in the method. Is .extractPredicate() a decent way to go about this in my case? Or is there something more idiomatic or clearer?


interface Predicate&lt;T&gt; {
  (x: T) : boolean
}

class PredicateBuilder&lt;T&gt; {
  condition: Predicate&lt;T&gt;;

  constructor(condition: Predicate&lt;T&gt;) {
    this.condition = condition;
  }

  public and(input: PredicateBuilder&lt;T&gt; | Predicate&lt;T&gt;): PredicateBuilder&lt;T&gt; {
    const p: Predicate&lt;T&gt; = this.condition;
    const q: Predicate&lt;T&gt; = this.extractCondition(input);

    return new PredicateBuilder((x: T) =&gt; p(x) &amp;&amp; q(x));
  }

  public or(input: PredicateBuilder&lt;T&gt; | Predicate&lt;T&gt;): PredicateBuilder&lt;T&gt; {
    const p: Predicate&lt;T&gt; = this.condition;
    const q: Predicate&lt;T&gt; = this.extractCondition(input);

    return new PredicateBuilder((x: T) =&gt; p(x) || q(x));
  }

  public not(): PredicateBuilder&lt;T&gt; {
    return new PredicateBuilder((x: T) =&gt; !this.condition(x));
  }

  public apply(x: T): boolean {
    return this.condition(x);
  }

  private extractCondition(input: PredicateBuilder&lt;T&gt; | Predicate&lt;T&gt;): Predicate&lt;T&gt; {
    let condition: Predicate&lt;T&gt;;
    if ("condition" in input) {
      condition = input.condition;
    } else {
      condition = input;
    }

    return condition;
  }
}


Playground Link including a small set of unit tests
As pointed out as a comment, I was unhappy about the extractCondition function.
This function handles, variables which do conform your Predicate&lt;T&gt; type. Which is fine, but I think this doesn't belong here.
Because a Predicate should have an accept or, if we talk about the Java implementation, test function.
This is not given when we can pass on any random function which do return a boolean. But does not conform our design of a Predicate.

Next naming, the PredicateBuilder seems okay-ish, but it feels wrong. As it isn't a builder in the classical sense.
Furthermore we have to work around functional interfaces, and this is I think the main pain point. To achieve this I would propose to rename the Predicate&lt;T&gt; interface, as it should be describing what a Predicate holds (a function which takes a parameter and returns a boolean). Therefore the name Predicate is available again and should be used instead of PredicateBuilder.

The repetition regarding and, or, etc... feels also some kind off. But I think that's because you always do extractCondition and other stuff (I've eliminated this in my suggestion, as the Java Predicate implementation does basically the same). Plus I've create a static method Predicate#of(...) to easier "get" a new Predicate. This reduces the mess a bit, but changing the operands is also still a bit clumsy, in my opinion.

Oh and btw. I've felt free to use arrow functions :-)

interface InternalPredicate&lt;T&gt; {
  (x: T) : boolean
}

class Predicate&lt;T&gt; {
  constructor(private condition: InternalPredicate&lt;T&gt;) {}

  public static of = &lt;T&gt;(condition: InternalPredicate&lt;T&gt;) =&gt; {
    return new Predicate(condition);
  }

  public and = (input: Predicate&lt;T&gt;): Predicate&lt;T&gt; =&gt;
    Predicate.of((x: T) =&gt; this.apply(x) &amp;&amp; input.apply(x));

  public or = (input: Predicate&lt;T&gt;): Predicate&lt;T&gt; =&gt;
    Predicate.of((x: T) =&gt; this.apply(x) || input.apply(x));

  public not = (): Predicate&lt;T&gt; =&gt;
    Predicate.of((x: T) =&gt; !this.apply(x));

  public apply = (x: T): boolean =&gt; this.condition(x);
}


Those are my two cents to the Predicate implementation, feel free to discuss them with me.

Alternative solution to eliminate the InternalPredicate and to support functions which are booleans:

type PredicateType&lt;T&gt; = (x: T) =&gt; boolean;

class Predicate&lt;T&gt; {
        constructor(private condition: PredicateType&lt;T&gt;) {}

        private static isInstance = &lt;T&gt;(input: Predicate&lt;T&gt; | PredicateType&lt;T&gt;): Predicate&lt;T&gt; =&gt; (input instanceof Predicate) ? input : Predicate.of(input);

        public static of = &lt;T&gt;(condition: PredicateType&lt;T&gt;) =&gt; new Predicate(condition);

        public and = (input: Predicate&lt;T&gt; | PredicateType&lt;T&gt;): Predicate&lt;T&gt; =&gt;
          Predicate.of((x: T) =&gt; this.apply(x) &amp;&amp; Predicate.isInstance(input).apply(x));

        public or = (input: Predicate&lt;T&gt; | PredicateType&lt;T&gt;): Predicate&lt;T&gt; =&gt;
          Predicate.of((x: T) =&gt; this.apply(x) || Predicate.isInstance(input).apply(x));

        public not = (): Predicate&lt;T&gt; =&gt;
          Predicate.of((x: T) =&gt; !this.apply(x));

        public apply = (x: T): boolean =&gt; this.condition(x);
}


It comes pretty close the the extractCondition approach, but the main difference here is, that a new instance is created if the input is a raw function. This adds up to be more robust to changes and being less error prone. Another advantage is, we don't care about how the predicate internally works, we're just in charge of returning a predicate based on the input. This clears up the use case of the function a bit more. 

EDIT: As discussed in the comments, it is nicer to merge the private isInstance function into the static of function.