2
votes

I am not sure if I found a bug in the interface/compiler from Fable or I misused the type system/externs.

Today I got a highly frustrating bug. As usual I typed externs to small functions I wrote in JS and one of them was returning a list of objects from a NOSQL database. Apparently fable received the object good. However when I tried to transform the object the code died without any error or explaination in an inconsistent fashion.

Because the code was complex with promises, parsing and other moving parts it took me many hours to find out the guilty part and the causes but finally I realized the JS array was not matching the F# List properly and the only way I found to move on was the following:

type IJSInterface =
    abstract FetchPosts: string -> JS.Promise<DBPost list>

...

// Transform Javascript array to F# normal list
let postList = straightJSArrayWithTypedPosts |> List.toArray |> Array.toList

My question is: Which is the recommended way to interface with javascript arrays? Because I read all the documentation I could and I couldn't find any precise instructions about this part. And I see it personally more as a bug. In fact I wish I could ban this "feature" with compiler errors or have immediate array safe interop between javascript and F#. Is there such compiler option? How could the compiler avoid to make me spend a whole Sunday in such issues? Is there any flag or something?


Edit: as guessed in the answer the omitted javascript code was in fact returning a javascript array which is not the same as a list, Although both are very similar, they aren't the same in spite of behaving equally for most of purposes in dynamic languages.

1

1 Answers

3
votes

If I understand the question correctly, the problem is that your JavaScript API is returning arrays, but you would like to view those as F# lists instead.

The way the typing for external APIs work in Fable is that you have to define the type "as it is generated by external JavaScript API". The compiler will not do any conversions and it will not attempt to check this at runtime, so you just have to get this right. If you use list in a place where the actual JavaScript API generates an array, then your typing for an external library is wrong.

So, in this case, I think you should just use:

type IJSInterface =
    abstract FetchPosts: string -> JS.Promise<DBPost[]>

This gives you somewhat less nice F# API, but that's to be expected when you are calling JavaScript code.