Differences from Fable
Each row is a case in the repository's tests/Differences folder. The differences workflow compiles each case with Fickl and with the latest Fable, runs it with Node.js, and rewrites this table on main. A case leaves the table once Fable passes it too.
What Fickl gets right that Fable 5.27.0 does not, checked by compiling each case in tests/Differences with both and running it with node. A case leaves this table once Fable passes it too.
| Change | Fickl | Fable 5.27.0 | Issues |
|---|---|---|---|
Name and FullName of an anonymous record type | An anonymous record type has a non-empty Name and FullName that tell different anonymous record types apart. | compiles, but fails at runtime: expected false, got true | #275 |
explicit constructors in an [<AttachMembers>] class | Constructing an [ | compiles, but fails at runtime: expected 1b, got 1undefined | #334 |
[<AugmentGlobal>] and [<AugmentModule>] | An interface marked [<AugmentGlobal>] or [<AugmentModule>] adds its members to a global or module interface in TypeScript, `declare global { interface HT... | doesn't compile: Unknown argument: --declaration | #154 |
BigInteger.Parse and TryParse with NumberStyles | BigInteger.Parse and TryParse honour the NumberStyles argument, reading HexNumber digits as two's complement, instead of ignoring it or throwing a Ty... | compiles, but fails at runtime: The value could not be parsed. | #262 |
[<CallableInterface>] | An object expression implementing a callable interface compiles to a plain JavaScript function, and keeps a generic Invoke generic. | doesn't type-check: The namespace or module 'Fickl' is not defined. | #8, #10, #11 |
| catching values JavaScript throws | :? JS.TypeError and the other Fickl.Core.JS error bindings catch JS errors by type, JS.Thrown matches a thrown value that is not an error, and `e.Messa... | doesn't type-check: The namespace or module 'Fickl' is not defined. | #158 |
--clampByteArrays | Compiles byte arrays as Uint8ClampedArray, the type canvas pixel data uses, so they can be passed to it without a copy. | doesn't compile: Unknown argument: --clampbytearrays | #39 |
ResizeArray.Sort, Array.Sort and Comparer<string>.Default on strings | The .NET comparer paths order strings like String.CompareTo, so lower case sorts before upper case, while F#'s compare and List.sort stay ordinal. | compiles, but fails at runtime: expected ["a"; "A"; "b"; "B"], got ["A"; "B"; "a"; "b"] | #271 |
[<Curried>] on a parameter | Keeps a function parameter curried, for JavaScript that calls it one argument at a time. | doesn't type-check: The namespace or module 'Fickl' is not defined. | #24 |
[<Curried>] on a record field | Keeps a function stored in a record field curried, for a JS object that stores or calls it one argument at a time. | doesn't type-check: The namespace or module 'Fickl' is not defined. | #41 |
| functions with more than 20 curried arguments | A function value with more than 20 curried arguments can be passed, called and partially applied. | compiles, but fails at runtime: The requested module './fable_modules/fable-library-js.5.27.0/Util.js' does not provide an export named 'uncurry22' | #291 |
Equals and CompareTo on DateOnly, TimeOnly and TimeSpan | Equals and CompareTo on DateOnly, TimeOnly and TimeSpan are implemented. | compiles, but fails at runtime: The requested module './fable_modules/fable-library-js.5.27.0/DateOnly.js' does not provide an export named 'compareTo' | #318 |
offsets in DateTimeOffset.Parse | DateTimeOffset.Parse of an ISO string keeps the offset written in it, not the local one. | compiles, but fails at runtime: expected 7200000, got 0 | #268 |
out-of-range dates in DateTime parsing | DateTime.TryParse rejects a day or month out of range, such as 2020-02-30, instead of rolling it over. | compiles, but fails at runtime: expected false, got true | #270 |
--declaration | Writes a TypeScript declaration file next to each JavaScript file, so TypeScript can call the compiled F#. | doesn't compile: Unknown argument: --declaration | #20, #21 |
| a binding with effects before a throw | A binding whose value has effects runs where it is declared, not after or inside a later throw. | compiles, but fails at runtime: expected ["v"; "threw"], got ["threw"] | #408 |
[<EmitType>] | Writes the TypeScript annotation of a type as the given text, for conditional, mapped and template literal types F# cannot describe; the JavaScript is unchan... | doesn't compile: Unknown argument: --declaration | #145 |
[<CaseTest>] on erased union cases | A JavaScript predicate tells apart erased cases with the same payload type, here two strings. | doesn't type-check: The namespace or module 'Fickl' is not defined. | #7 |
| option fields ending an erased tuple | Trailing option fields of an erased single-case union are optional tuple elements, so FetchArgs("/", None) is ["/"], and named fields label the elements ... | doesn't compile: Unknown argument: --declaration | #153 |
operators of an [<Erase>] union | A custom operator of an erased union is used when an operand is built with the case constructor, not the native operator. | compiles, but fails at runtime: expected 6, got 3 | #280 |
explicit constructors of a class inheriting System.Exception | A class with only explicit constructors that inherits System.Exception extends it and keeps the message passed to the base. | compiles, but fails at runtime: expected boom, got undefined | #334 |
members of a failed Regex match | Value, Index, Length and Groups of a failed match give .NET's empty-match values instead of throwing. | compiles, but fails at runtime: Cannot read properties of null (reading '0') | — |
the FICKL_COMPILER define | Defines FICKL_COMPILER, so code can choose Fickl.Core or Fable.Core when both have an attribute. | compiles, but fails at runtime: expected fickl, got fable | #43 |
| float ranges | Each item of a float range is computed from the start, so rounding errors do not add up and drop the last item. | compiles, but fails at runtime: expected 21, got 20 | — |
overloads taking 'T -> 'U and Func<'T, 'U> | Overloads that differ only by a function or a delegate parameter get different names. | doesn't compile: FABLE: Cannot have two module members with same name: DelegateOverload_Map_5ACDD93 | #287 |
importValueDynamic of a function | importValueDynamic works with tupled and curried functions, called with their compiled signature. | doesn't compile: FABLE: The imported value is not coming from a different file | #314 |
[<InlineInterface>] | A TypeScriptTaggedUnion case holding one interface compiles as that interface with the tag added, { type: "take", fromIndex, toIndex }. | doesn't type-check: The namespace or module 'Fickl' is not defined. | — |
Int32.Parse with signs, radix prefixes and underscores | Int32.Parse rejects 0x, 0b, 0o and _ as .NET does, and with HexNumber takes neither a sign nor a 0x prefix. | compiles, but fails at runtime: expected true, got false | #261 |
[<JsError>] | An F# exception marked [<JsError>] is a JS Error subclass with a stack, and still matches and compares as an F# exception. | doesn't type-check: The namespace or module 'Fickl' is not defined. | #157 |
| members of a class inheriting a JavaScript class | A class whose base is a global or imported JavaScript class attaches its members, so JavaScript sees static observedAttributes and its methods. | compiles, but fails at runtime: Cannot read properties of undefined (reading '0') | #162 |
--temporal | Represents dates and times with the JavaScript Temporal API, a documented flag for Fable's hidden --test:js-temporal. | doesn't compile: Unknown argument: --temporal | #39 |
keyof<'T> and keyof<'T, 'R> property keys | keyof _.Port is the property's JavaScript name, typed keyof T & string or KeysOfType<T, R> in TypeScript, and KeyOf.get/KeyOf.set index an object b... | doesn't compile: Unknown argument: --declaration | #174 |
Match.NextMatch() | Match.NextMatch() is implemented, resuming the search after the current match. | compiles, but fails at runtime: The requested module './fable_modules/fable-library-js.5.27.0/RegExp.js' does not provide an export named 'nextMatch' | #343 |
copying a mutable struct record | { m with ... } and a byref to a mutable struct record read the struct's fields, not those of a reference cell. | compiles, but fails at runtime: expected , got | #254 |
--nativeErrors | Every exception, from failwith to a declared F# exception, is a JS Error with a stack, and an inner exception is its cause. | doesn't compile: Unknown argument: --nativeerrors | #157 |
[<NoOverloadSuffix>] | Drops the overload hash from a method's compiled name, Counter__Add instead of Counter__Add_Z524259A4, so JavaScript can call it by a predictable name. O... | doesn't type-check: The namespace or module 'Fickl' is not defined. | #35 |
partial and Partial<'T> | partial builds an object with some of a type's properties, typed Partial<T> and checked with satisfies in TypeScript instead of cast to the full type. | doesn't compile: Unknown argument: --declaration | #151 |
| an explicit class inheriting a class with a primary constructor | The class extends its base, so { inherit Base("derived"); Extra = 5 } has its Name. | compiles, but fails at runtime: expected derived, got undefined | #96 |
let fields of a class inheriting a JavaScript class | The fields are ES #private fields, so let size in a subclass of Map does not try to set Map's read-only size. | compiles, but fails at runtime: Cannot set property size of # | #161 |
--privateFields | Compiles the let fields of every class with attached members to ES #private fields, which JavaScript cannot read or enumerate. | doesn't compile: Unknown argument: --privatefields | #161 |
indexing an IReadOnlyList<'T> | xs.[i] on an IReadOnlyList indexes an array, a ResizeArray or an F# list instead of calling a .NET member name that arrays do not have. | compiles, but fails at runtime: xs.System.Collections.Generic.IReadOnlyList`1.get_ItemZ524259A4 is not a function | #431 |
| read-only collections in TypeScript annotations | IReadOnlyCollection, IReadOnlyList and IReadOnlyDictionary are annotated as types a TypeScript readonly array or ReadonlyMap satisfies instead of `an... | doesn't compile: Unknown argument: --declaration | #146 |
ReflectedDecorator member names | The MethodInfo given to a ReflectedDecorator has the member's own name, not the mangled declaration name. | compiles, but fails at runtime: expected ["decorated function"; "StaticMember"], got ["decorated$0020function"; "Decorated_StaticMember_Z524259A4"] | #276 |
[<ReturnsThis>] | An abstract method returning its own interface is declared returning this in TypeScript, so a subinterface keeps its members through a chain of calls; the ... | doesn't compile: Unknown argument: --declaration | #152 |
--strictOptions | Some null of a string, array, class, record or function stays Some, as on .NET, built the same way at concrete and generic sites. Value options stay erased. | doesn't compile: Unknown argument: --strictoptions | #32 |
[<StructuredFormatDisplay>] | %A, %O, string and interpolation print a record or union with its [ | compiles, but fails at runtime: expected Foo , got | #266 |
TimeSpan ticks | TimeSpan.FromTicks keeps sub-millisecond ticks and reads back Int64.MaxValue, and ToString prints all seven fraction digits. | compiles, but fails at runtime: expected 1, got 0 | #264 |
[<TsEnum>] and imported [<StringEnum>] unions | Emits a [<TsEnum>] enum as the object a TypeScript enum compiles to, typed by an ambient enum in TypeScript, and compiles the cases of an imported or globa... | doesn't type-check: The namespace or module 'Fickl' is not defined. | #149 |
Record<'K, 'V>, ReadonlyRecord and PropertyRecord | Fickl.Core.Record<'K, 'V> is a plain object typed Record<K, V> in TypeScript, with ReadonlyRecord and PropertyRecord for Readonly<Record<K, V>> and... | doesn't compile: Unknown argument: --declaration | #175, #142 |
unknown, an abbreviation of obj | A module function or abstract member taking or returning Fickl.Core.unknown has unknown in its TypeScript signature, so TypeScript callers must narrow th... | doesn't compile: Unknown argument: --declaration | #150 |
[<TypePredicate>] and [<TypeAssertion>] | Emits a function as a TypeScript type guard, x is T or asserts x is T, while F# calls it as returning an option or a Result of the narrowed argument. | doesn't type-check: The namespace or module 'Fickl' is not defined. | #147 |
a function parameter passed to ==> or ?<- | A two-argument function that reaches ==> or ?<- through a member parameter is uncurried, so JavaScript can call it with two arguments. | compiles, but fails at runtime: expected member 1 x, got (a2) => f(a1, a2) | #289 |
valueof<'T> for T[keyof T] | Fickl.Core.valueof<'T> is the value of some property of 'T, typed T[keyof T] in TypeScript, built with ValueOf.ofKey and read as a type with a visibl... | doesn't compile: Unknown argument: --declaration | #177 |