Skip to content
0.9 Compatible with Fable projects.

fickl

F# to JavaScript and TypeScript, faster and more explicit.

A fork of the Fable compiler that adds what JavaScript and TypeScript projects need: native async and generators, TypeScript declarations, typed interop and a switch for every implicit change.
Swap dotnet fable for dotnet fickl; Fable's attributes and functions keep working.

open Fable.Core
open Fickl.Core

type User = { Name: string; Age: int }

[<Global>]
let fetchUser (id: int) : JS.Promise<User> = jsNative

[<AsyncFunction>]
let adultNames () = jsAsync {
    let! first = fetchUser 1
    and! second = fetchUser 2
    return
        [ first; second ]
        |> List.filter (fun u -> u.Age >= 18)
        |> List.map _.Name
}
import { Record } from "@fable-org/fable-library-js/Types.js";
import { record_type, int32_type, string_type } from "@fable-org/fable-library-js/Reflection.js";
import { ensureResolvedAsyncValue } from "@fable-org/fable-library-js/Util.js";
import { ofArray, filter, map } from "@fable-org/fable-library-js/List.js";

export class User extends Record {
    constructor(Name, Age) {
        super();
        this.Name = Name;
        this.Age = (Age | 0);
    }
}

export function User_$reflection() {
    return record_type("Example1.User", [], User, () => [["Name", string_type], ["Age", int32_type]]);
}

export const adultNames = async function () {
    const _arg = await Promise.all([fetchUser(1), fetchUser(2)]);
    return ensureResolvedAsyncValue(map((_arg_1) => _arg_1.Name, filter((u) => (u.Age >= 18), ofArray([_arg[0], _arg[1]]))));
};
import { Record } from "@fable-org/fable-library-ts/Types.ts";
import type { int32 } from "@fable-org/fable-library-ts/Int32.ts";
import { ensureResolvedAsyncValue, type IComparable, type IEquatable } from "@fable-org/fable-library-ts/Util.ts";
import { record_type, int32_type, string_type, type TypeInfo } from "@fable-org/fable-library-ts/Reflection.ts";
import { type FSharpList, ofArray, filter, map } from "@fable-org/fable-library-ts/List.ts";

export class User extends Record implements IEquatable<User>, IComparable<User> {
    readonly Name: string;
    readonly Age: int32;
    constructor(Name: string, Age: int32) {
        super();
        this.Name = Name;
        this.Age = (Age | 0);
    }
}

export function User_$reflection(): TypeInfo {
    return record_type("Example1.User", [], User, () => [["Name", string_type], ["Age", int32_type]]);
}

export const adultNames = async function (this: any): Promise<FSharpList<string>> {
    const _arg: [User, User] = await Promise.all([fetchUser(1), fetchUser(2)] as [Promise<User>, Promise<User>]);
    return ensureResolvedAsyncValue<FSharpList<string>>(map<User, string>((_arg_1: User): string => _arg_1.Name, filter<User>((u: User): boolean => (u.Age >= 18), ofArray([_arg[0], _arg[1]]))));
};

Compiled by this build of Fickl when the site was built.

Why Fickl

Fickl is a lab for the JavaScript and TypeScript side of Fable. Its priorities, in order: the performance and ergonomics of the compiler, explicit control of the code it emits, the performance and ergonomics of JavaScript interop, TypeScript interop, and transparent diagnostics.

What Fickl gets right that Fable does not

Each case in the repository's tests/Differences is compiled with both compilers and run with Node.js on every change to main. A case leaves the list once Fable passes it too. See Differences from Fable for the current list.