I was pleasantly surprised how far the type system goes though. Thanks to structural typing I get the pipe operator even for things I do not declare as SignalTransformers in the following:<p><pre><code>  interface SignalFn&lt;T&gt; {
      (time: number): T;
  }

  interface SignalTransformer&lt;A, B&gt;{
      (a: SignalFn&lt;A&gt;): SignalFn&lt;B&gt;
  }

  &#x2F;&#x2F; the &gt;&gt;&gt; function
  function pipe&lt;A,B,C&gt; (a: SignalTransformer&lt;A,B&gt;, b: SignalTransformer&lt;B,C&gt;): SignalTransformer&lt;A,C&gt; {
      return (x: SignalFn&lt;A&gt;) =&gt; b(a(x))
  }

  &#x2F;&#x2F; the arr lift
  function lift&lt;A, B&gt;(fn: Function1&lt;A,B&gt;): SignalTransformer&lt;A,B&gt; {
      return (input: SignalFn&lt;A&gt;) =&gt; &lt;SignalFn&lt;B&gt;&gt;((time: Time) =&gt; fn(input(time)));
  }</code></pre>