F# Interop with Javascript in Fable: The Complete Guide

Fable, the F# to Javascript compiler, always had the motto “The compiler that emits JavaScript you can be proud of.” That is true, the generated javascript code is readable and idiomatic, sometimes — I can’t believe I am saying this about Javascript — It is even beautiful. However, Fable has another killer feature which will be the subject of this article: simple interop with the Javascript ecosystem.

Interop with Javascript means that you would write F# code that calls native javascript functions. In the more general sense, it lets you generate custom javascript code you control. Also it lets interact and use javascript code and libraries in your code.

In this article I will present you a plethora of examples on how and when to use Javascript interop. I will be covering a lot, so grab yourself a cup of coffee and lets get started.

Enviroment Setup

Skip this section if you already know how to setup a minimal Fable app.

We will use a local developement enviroment. To get started you will need the latest dotnet cli, Node and npm installed on your machine. Npm is packaged with Node so you don’t need a seperate download.

Lets a create a directory for our project:

mkdir FableInterop
cd FableInterop

If you are working with Fable for the first time you need to run this once:

dotnet new -i Fable.Template::*

It will download the latest fable template project from Nuget and cache it on your machine.

Now inside FableIntero directory you can run dotnet new fable which will generate a minimal fable app from the template. As for the editor I am using VS Code with Ionide for cross-platform F# developement.

After you have the project, you need to install it’s dependencies, this could take a couple of minutes (at least on my machine):

npm install
dotnet restore

When this finishes, you should have tooltips and auto-completion working inside VS Code.

Working with Fable is a bit tricky, you need 2 things to be working simultaneously for an “edit-save-recompile” flow, I usually use 2 shell tabs: One for running Fable compilation server using dotnet fable start , Fable works behind a local server to cache compilation states when it recompiles a project after a change in a file, making subsequent compilations fast. Second tab is for running Webpack developement server using npm run start that actually watches the changes in your project and sends them to the Fable server. Webpack is also responsible for serving your static content, bundling your code and refreshing the the browser when a recompilation is succesful.

Working with the code

Inside the src/App.fs you can delete everything and leave this:

Keep Fable.Core and Fable.Core.JsInterop open as they provide the functions and attributes for the interop. The Fable.Import.Broweser is opened only for using console.log and it is generally recommended you fully qualify the the Browser module if you want to use function from there, i.e. Browser.console.log, here I am using it like the above for brevity.

For now we will only use src/App.fs . To start developement mode, you can run the command:

dotnet fable npm-run start

This will start off two processes, one for Fable compilation server and one for Webpack developement server, these will work together when you make changes to your code for fast recompilations. Alternatively you can run each server seperately: run dotnet fable start and on shell tab and in another tab, run npm run start . Navigate to http://localhost:8080 and open your browser console, you should see this:

From now on, you can just edit and save your App.fs file and come back to the browser or console and see the changes.

The [<Emit>] Attribute

This is an attribute that you can attach to values, functions, members and other language constructs to override their default code generation. Next are some of the many use-cases of this attribute.

Defining the undefined

Javascript has a literal value known as undefined. F# does not have such construct. We will use the Emit attribute to generate that value in the following example:

Notice the parts: [<Emit("undefined")>] , obj and jsNative . The string “undefined” in the [<Emit>] is called the “emit expression” , it is what gets injected in place of the undefined value when the code is compiled. obj is the type you give to the value. In this case an obj is correct because undefined could be any object in javascript. The right hand side of the assignment is ignored during compilation, due to the fact that there is an [<Emit>] attribute. If this attribute is omitted, jsNative will throw an error.

This way you can define custom values with their own types and use them regularly in your fsharp code. To inforce the concept, here is another example:

Whenever the compiler comes across the value one , it will just inject the literal value within the [<Emit>] . In this case it is 1. Another thing to notice is the fact that it had the type of int , this in turn allows me to use the + operator because the type checker thinks it is an integer, which is the correct type in this case.

You have to be careful to always write the correct types becuase otherwise the code will just fail during runtime and cause unexpected behavior.

Generating literal code (like in the examples above) has it’s uses but is not very useful. The real fun starts when you parameterize the emit expression: using [<Emit>] with functions, giving them macro-like behavior!

Parameterized [<Emit>] with functions

To extend our first example, I want to write a function that checks whether or not a value is undefined , here is the example:

Now, take a closer look at the function isUndefined . It has one paramter called x of a generic type 'a . The function returns bool . Then notice that $0 in the emit expression , that is a placeholder of whatever value you pass to the function in the place of parameter x . It has the number 0 because the parameters are 0-indexed and therefore the first parameter (in this case x ) will have the index 0. Multiple parameters are also allowed (example):

Another useful example is when you want to check whether or not a value is not a number (NaN) using the native isNaN function:

You might want to call a function without paramters and get a result, for example if you want a random number using the native Math.random() :

Actually, System.Random is supported by Fable so you can use that too. Here I am just showing you what you can do.

Type-safe Javascript functions with Option<’t>

The type Option<'a> has special usage with Fable, namely that it is erased when compiled. Some x becomes just x and None becomes null . We will use this to give native functions type-safety. For example, the function parseFloat has a type of string -> float. parseFloat might fail parsing the input string and return a NaN, I know NaN is a valid value for float but for the sake of better semantics, we want to use the type: string -> Option<float> and return None when the return value is NaN. We can wrap the native function inside a typed one and use pattern matching:

The [<Emit>] expression for parseFloatfollows the logic: parseFloat could return NaN , Therefore I check if the result of parsing is NaN and return null if that is the case and otherwise return the parsed value. Giving this function a return type of float option makes it convenient to work with such functions, this way I ensure that my code has to account for failure of parsing and make sure to handle the case of None too.

However, this approach is still not very robust because the parsing succeeds with input “5x” and returns 5 instead of failing like it should. This is more of a limitation of the native function itself and to correctly parse numbers, we will use a little javascript trick to do that. Putting the + operator before a string will parse a string to a number! Why that works I hear you say? I don’t know, your guess is as good as mine, good reasons I hope:

Notice that I used + twice in that emit expression and passed the parameter twice as well, which is not very efficient if my parameter was the result of an expensive operation. It should be wrapped inside a lambda (for proper scoping) and used only once:

You can still use the parse functions from the BCL such as System.Int32.(Try)Parse, System.Double.(Try)Parse etc. They are implemented to mimic the actual behavior from .NET as much as possible.

Writing a JQuery binding, it’s just glue.

We will use what we have learnt so far to write a jQuery binding. A binding is a collection of functions that call the functions of the original api. In this case the native library is JQuery.

First of all, add a reference to JQuery in your public/index.html file with a script tag and include it before your bundle.js file. index.html should look something like:

Notice that when the page loads, jQuery’s $ will be available globally to be called in the page. Another place to reference the dollar sign is directly from the window object like this window.$ or this window['$'] .

We will use just the [<Emit>] to write the binding. Lets assume we want to make this binding functional-ish. It goes as follows: define a jQuery instance type, this will be an empty type just to tell when a function returns a jQuery element or something else:

Making this type an interface will ensure the type does not generate any extra code, it is only there for the type checker. Now we define our JQuery module, first you think about how you want to use the binding. I want to be able to use it in a functional style the same way I use Seq, Async or List etc:

I want it to generate something like the following with chaining:

const div = window['$']("#main")
div.css("background-color", "red")
.click(function(ev) { console.log("Clicked")})
.addClass("fancy-class");

Notice I will use JQuery.select as an alias of $ . I will need a refence to that dollar sign but I can’t just use it like [<Emit("$(...)")>] because the dollar sign is reserved for emit expressions. However, inside a browser, every globally available variable is just a property on the window object. So I can get a reference to $ from the window like this:

Notice that when putting $ between quotes it becomes an allowed emit expression.

The other methods are defined in a similar way like we have seen before:

And so on and so forth for the rest of the functions if you want to support all of JQuery. Notice that, in order to enable chaining, I am passing el as the last parameter of type IJQuery and returning IJQuery (most JQuery functions return a JQuery object, see docs). This makes for a nice functional API although it is just my personal preference.

Instance-based method chaining for the JQuery binding

Writing a jQuery binding as a module is one just one way to enable chaining jquery methods. I bet you expected the usual way of chaining methods is to “dot through” the api:

This requires having the methods placed on the instance type rather than on a module. Earlier we used the interface ‘IJQuery’ but it was empty, this time we will fill that interface with abstract methods:

Observations:

  • using abstract methods to only define their type signatures.
  • abstract methods without an emit attribute are compiled using the name of the method.
  • for custom-named functions such as onClick I am using [<Emit>] to fall back to the actual name, that is click . The instance itself will be the first parameter that’s why I am using $0.click($1) where $0 is the instance and $1 is the argument.
  • the css has a paramter as a tuple to correctly compile to javascript. If I used parameters such as css : string -> string -> IJQuery I would not be able to “dot through” the code and would have to use css with it’s paramters between parentheses.
  • I kept using the JQuery.select to start the “chain”.

To be used like this:

Will produce:

If you don’t like giving everything a type, you can go quick-and-dirty with dynamic programming capabilities of Fable, although I personally discourage using this model because one of the main reasons for chosing F# to compile to javascript is the powerful type-system and if I wanted to write dynamic code I wouldn’t bother to use Fable in the first place. Anyways, each to his own, you might like this model so here it is:

Working with object literals

JQuery among almost every other javascript library, works with object literals. They are used as paramters most of the time and they are ubiquitous.

Using Fable. We want to be able to create and manipulate object literals in a type-safe way. There are multipe ways of doing that. For example, assume I have the imaginary function in javascript addTime that is natively used like this:

As you can see, the object literal consists of three properties: current has type Date (in javascript). amount has type number and unit is a string. To represent these types in F# we would use DateTime for current , int for amount and string for unit . We will use a type to represent the whole object literal like the following, lets call it AddTimeProps :

This will output this:

A simple object literal becomes the output which is exactly what the external function addTime is expecting. Notice that because AddTimeProps does not have any constructors, I used the createEmpty<T> function. This is a special Fable function that will create an empty object literal but with the given type paramter T . In this case T is AddTimeProps . Also notice that we are not using [<Emit>] with the properties. That is because they are abstract and Fable will use the name of the property provided. To use custom names, you can use the [<Emit>] attribute but with a funny emit expression syntax like this:

Here I am replacing the property amount with specialAmount using [<Emit>] then it produces the property with the custom name, it is using “optional parameter” syntax to determine whether it should use the setter or the getter for the property.

String Literal Types, only better

Now, you might be satisfied with this solution for type-safety but you can actually do better! Suppose you are reading the docs of addTime and come across the information that the property unit can only have string values “days”, “months” or “years”. To ensure that no one forgets these values or write them incorrectly we want the compiler to check the correctness our code. For this case we can use the [<StringEnum>] attribute. This is similar to “string-typing” in typescript. You can define a discriminated union with cases that don’t have paramters and have them compiled to strings at compile-time. Here is an example:

We can use this to enhance the AddTimeProp type with even more type-safety by changing the type of unit from string to TimeUnit :

The case of the discriminated union is camel-cased when compiled. If you need a custom name for your union case such as “YEARS” instead of “year”, you can use the [<CompiledName>] attribute applied to the case:

The output becomes:

Using [<Pojo>] Attribute

Plain old javascript objects or POJOs is just another name for object literals. Fable provides a useful attribute [<Pojo>] that is applicable to record types to make them compile to object literals, here is an example:

This does not change the fact that they are still immutable. However, you can still start with an empty object using the createEmpty<T> function:

A note from Fable’s author, Alfonso Garcia-Caro:

Pojo records are only intended for type-safe interaction with javascript libraries that require a plain object (like React components). These records lack many features, like instance and static methods and have no reflection support.

Using a list of discriminated union as object literal

Yes, that is also possible! To use the previous example of Person , this is how you would describe it as a discriminated union:

A Person has these properties of Name and Age but because this is a sum type, you can either have Name or Age to be a person which does not make sense. In order for this to work, you actually need a list of Person :

Not quite idiomatic in F# but it works well (and looks nice) when interacting with external libraries. Now that you have the list of Person, you can use the special function keyValueList provided by Fable (in Fable.Core.JsInterop) to turn that list into an object literal:

These type of object literals should be used you have many optional properties of an object and you want a couple of them and you ignore the rest. This works pretty well for example for React style objects or for JQuery’s ajax options.

You can all also use ad-hoc properties using unbox or using the new dynamic operator !!:

It it worth noting that Fable will try to convert the list to an object literal during compile-time if the value is constant and in run-time if the value is yet to be determined during run-time.

Creating object literals inline

Again, if you feel lazy and you don’t want to give everything a type, you can another Fable function called createObj from Fable.Core . This function creates an object literal like this:

createObj is nice becuase it accepts a list of key-value pairs just like what would expect from an object literal. You can easily nest objects too:

Interacting with existing Javascript code

All our interaction with javascript so far was through generating some custom code that will be injected during compilation using the different attributes and functions that Fable provides. Now it is time to interact with existing javascript code and actually call it from F#. To learn this, we will write some javascript by hand. First create a file called custom.js like this:

This file will contain two functions that we will call from F#. parseJson and getValue organized using modules to be compatible with webpack:

parseJson will try to parse a string to an object literal and will return null if that fails. getValue will try to get a value from an object literal using it’s string index and will return null if such property does not exist (i.e. the property is undefined).

Because both functions will return either a result or null, that qualifies them to return Option<'a> . Also notice that this file is in the same directory src as the the App.fs file. When importing custom code, you use relative paths.

To import these functions, we will use the import function from inside App.fs like this:

The first argument for import is what value you want to import, in this case it is the function parseJson and the second argument is the where you want to import that value from, in this case from the file called custom.js in the same directory.

Now these functions are available to be used:

With the output:

Another way to import both functions or any number of functions from a javascript module is using the importAll function, but first you have to put declarations into one type and import all the functions from the javascript module as that type:

A javascript module can export a single value:

I created a file default.js inside src directory with the code above. You can import it using importDefault :

Interacting with Javascript from npm packages

Modern javascript libraries are distributed through npm, the node package manager, as modules. Less often are there “built and ready” libraries that you just add to your page with a script tag. In our Fable apps we definitely want to interact such libraries. For the following example I want to use a silly library called left-pad. I call it silly because this “library” is a single function used by millions, instead of … you know, just writing the function yourself whenever you need it.

Anyways, I will stop ranting now :), here we go. It the same as with our custom.js file but instead of pointing to the path of library, you just point to the name of it. First you want to install the library using npm by running npm install --save left-pad. This package is then added as a dependency to your package.json file, you should see the entry "left-pad": "^1.1.3" in your dependencies . It is insalled in your node-modules directory and with the magic of Webpack, you can import it from anywhere in you F# code like this:

Working with overloads

If you look at the docs of left-pad, the function leftPad should have another overload with only two parameters. Because you can’t overload normal F# functions (like the one above) you can write the same function with a different (but meaningful) name with two parameters:

If you want to overload the method with the same name, you can use static methods on a class.

What about when you have a function with one paramter but that parameter can be a string, int or DateTime? Then you use “erased unions”. These special union types created just for overloading paramter types. To define a function with a such parameter:

If you had more types, you would use U4<>, U5<> etc. To use such functions you write:

Notice the funny !^ operator specially made to work with erased types and to check whether or not the provided type is actually compatible with parameter type.

Curried and Uncurried Functions

Functions in F# are curried by default, that is when using multiple arguments, the function becomes a single parameter function that returns other functions, here is an example:

This function is equivalent to this curried function:

In the early days of Fable, it used to compile the curried function as is with closures:

But recently as of Fable 1.0 beta, the compilation is optimized and the function is uncurried:

What if you wanted to explicitly return a function like this:

then you would have to use System.Func in the signature as the return type:

Conclusion

There are many ways to interact with javascript in Fable. This allows you to leverage all of the javascript ecosystem and the numerous libraries published on npm. I hope you learnt a lot from this article, don’t forget to hit that heart icon below and to share!