I have been reading through Tom Harding's blog series on the fantasy-land spec, and this afternoon I was playing around with implementing a functor in typescript.
class Just<T> {
  private x: T
  constructor (x: T) {
    this.x = x
  }
  map <R>(f: (a: T) => R): Just<R> {
    return new Just(f(this.x))
  }
}
class Nothing<T> {
  private x: T
  constructor (_: T) {
    // noop
  }
  map <R>(_: (a: T) => R): Nothing<R> {
    return new Nothing<R>(undefined)
  }
}
type Maybe<T> = Just<T> | Nothing<T>
const map1 = <T, R>(f: (a: T) => R, a: Maybe<T>): Maybe<R> => {
  return a.map(f)
}
Unfortunately, a.map(f) above results in the following compile time error:
[ts] Cannot invoke an expression whose type lacks a call signature. 
Type '(<R>(f: (a: T) => R) => Just<R>) | (<R>(_: (a: T) => R) => Nothing<R>)' 
has no compatible call signatures.
I feel like this should work though... I made a simpler example, which is not a functor, but which uses generics in most of the same ways:
class A<T> {
  private x: T
  constructor (x: T) {
    this.x = x
  }
  func <R>(f: (a: T) => R): R { // this is returning R not A<R>
    return f(this.x)
  }
}
class B<T> {
  constructor (_: T) {
    //
  }
  func <R>(_: (a: T) => R): R {
    return undefined
  }
}
type C<T> = A<T> | B<T>
const func = <T, R>(f: (a: T) => R, a: C<T>): R => {
  return a.func(f)
}
This code compiles just fine. If I change the return types of the functions to be A<R> and B<R> (ie, if map returns C<R>) then I get the same error as above.
So I'm wondering: what is up? Is this some crazy contravarience/covarience thing? Is this the expected behaviour of typescript? Is this just me missing something? (or is it nothing ^o^// ).
EDIT: I tried re-implementing the above with inheritance instead of a union:
abstract class Maybe<T> {
  protected x: T
  constructor (x: T) {
    this.x = x
  }
  abstract map <R>(f: (a: T) => R): Maybe<R>
}
class Just<T> extends Maybe<T> {
  constructor (x: T) {
    super(x)
  }
  map <R>(f: (a: T) => R): Just<R> {
    return new Just(f(this.x))
  }
}
class Nothing<T> extends Maybe<T> {
  constructor (_: T) {
    super(undefined)
  }
  map <R>(f: (a: T) => R): Nothing<R> {
    return new Nothing(undefined)
  }
}
const map2 = <T, R>(f: (a: T) => R, a: Maybe<T>): Maybe<R> => {
  return a.map(f)
}
It works just fine! What gives, typescript!?
Even thought the above works, this is not what I want. Just doesn't "extend" Maybe, Maybe is a union of Just and Nothing. It's my way of the highway
EDIT: EDIT: I tried it again using an interface for Functor
// tslint:disable-next-line:interface-name
interface Functor<T> {
  map: <R>(f: (a: T) => R) => Functor<R>
}
class Just<T> implements Functor<T> {
  private readonly x: T
  constructor (x: T) {
    this.x = x
  }
  map <R>(f: (a: T) => R): Just<R> {
    return new Just(f(this.x))
  }
}
class Nothing<T> implements Functor<T> {
  constructor (_: T) {
    // nop
  }
  map <R>(_: (a: T) => R): Nothing<R> {
    return new Nothing(undefined)
  }
}
type Maybe<T> = Functor<T>
const map3 = <T, R>(f: (a: T) => R, a: Maybe<T>): Maybe<R> => {
  return a.map(f)
}
This works too, and I'm more OK with saying that Just implements Functor's interface, because well... it does. I'm still not happy with type Maybe<T> = Functor<T> because it over-specifies the type (there are more members of Functor than Maybe?)
Also, I guess map needs to not just return Functor but the same Functor, like a Maybe's map returns a Maybe (not just any Functor). I'm beginning to see why we need higher-kinded types to represent this kind of stuff?
EDIT: Adding a second generic to account for the Kind of the functor seems to work. Now a Just's map must return a Just.
// tslint:disable-next-line:interface-name
interface Functor<K, T> {
  map: <R>(f: (a: T) => R) => Functor<K, R>
}
And then I define Maybe like this:
type Maybe<T> = Functor<Just<T> | Nothing<T>, T>
Fingers crossed.