I have hit the same problem. In my case, I don't want to use a union, because I need an open-ended number of types that could implement the interface. The types are known to the client code, but the server code only knows about the interface.

In the JS, the interface has object as its prototype, so any method calls fail at runtime. Downcasting doesn't help, since this is compiled to nothing in the JS. If I take a specific type, I can 'fix' the prototype by making a copy. For a record, I can do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

type IFruit with
abstract Eat: unit -> unit

[<JavaScript>]
type Banana =
{
Length: float
}

interface IFruit with
member __.Eat () = ()

let test (f: IFruit) =
let b = f :?> Banana // but b.Eat () will fail with missing function
let b2 = { b with Length = b.Length } // b2 has correct prototype
b2.Eat () // ok


But if I have many types that might implement IFruit, I have to know the specific type (e.g. Banana) before I can make the copy to fix the prototype.

What if the server also returns the System.Type? Is there some way I can use the runtime type to fix the prototype?

By on 12/11/2015 8:45 AM ()

I think I'm going to have to use a union for other reasons, but I'd still be interested to know if there's a general way to fix the prototype.

By on 12/11/2015 10:04 AM ()

There is actually no problem to compile interfaces and abstract classes to JavaScript. However, it seems you are trying to pass an interface through an RPC function, and that is not supported. Only records, discriminated unions, enums, and a number of built-in types can be passed through RPC.

By on 10/15/2014 10:12 AM ()

By on 10/17/2014 7:43 AM ()

I ended up just switching to using a discriminated union, with a match statement that mapped each element to a specific render function

By on 10/20/2014 12:53 AM ()