You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[<FSharp.Core.DefaultValue>] not handled properly on static fields #2739
When a static field has the [<FSharp.Core.DefaultValue>] attribute, Fable leaves its value as undefined, which can have different behavior than the .NET default value.
Root cause: Fable doesn't emit static field initializers in the generated JavaScript class body. In declareClassWithParams in src/Fable.Transforms/Fable2Babel.fs (~line 3467), the classFields array only adds TypeScript type-annotation declarations for fields; no default-value initialization is emitted for either JavaScript or TypeScript:
letclassFields=if com.IsTypeScript &¬ ent.IsFSharpUnion then
ent.FSharpFields
|> List.mapToArray (fun field ->// Comment in the source: "Static fields need to be initialized by static constructor"
ClassMember.classProperty (prop, isComputed = isComputed, isStatic = field.IsStatic,...))else
Array.empty // <-- nothing for JS
So a field like static val mutable private count : int with [(DefaultValue)] is never emitted as static count = 0; in the JavaScript output. At runtime Foo.count is undefined. When you compute undefined + 1, JavaScript produces NaN, and since integer arithmetic is coerced via | 0, NaN | 0 = 0, causing the method to return 0 instead of 1.
The fix would need to:
Add a makeDefaultValue function for the JS target (the Python target already has getDefaultValueForType in Fable2Python.Util.fs as a reference)
In declareClassWithParams, emit static count = 0; (or the appropriate default for the field's type) for static FSharpFields — either only when [(DefaultValue)] is present, or unconditionally for all static fields of value types
Note: PR #4405 (currently open) fixes a related but distinct issue — static backing fields for static member val being incorrectly included as constructor parameters. This [(DefaultValue)] initialization issue is a separate bug that will still need a fix after #4405 is merged.
Activity
chkn commentedon Jan 17, 2022
I found a workaround: save the static field to a local first. This works as expected:
github-actions commentedon Mar 17, 2026
🤖 This is an automated response from Repo Assist.
Root cause: Fable doesn't emit static field initializers in the generated JavaScript class body. In
declareClassWithParamsinsrc/Fable.Transforms/Fable2Babel.fs(~line 3467), theclassFieldsarray only adds TypeScript type-annotation declarations for fields; no default-value initialization is emitted for either JavaScript or TypeScript:So a field like
static val mutable private count : intwith[(DefaultValue)]is never emitted asstatic count = 0;in the JavaScript output. At runtimeFoo.countisundefined. When you computeundefined + 1, JavaScript producesNaN, and since integer arithmetic is coerced via| 0,NaN | 0 = 0, causing the method to return0instead of1.The fix would need to:
makeDefaultValuefunction for the JS target (the Python target already hasgetDefaultValueForTypeinFable2Python.Util.fsas a reference)declareClassWithParams, emitstatic count = 0;(or the appropriate default for the field's type) for staticFSharpFields — either only when[(DefaultValue)]is present, or unconditionally for all static fields of value typesNote: PR #4405 (currently open) fixes a related but distinct issue — static backing fields for
static member valbeing incorrectly included as constructor parameters. This[(DefaultValue)]initialization issue is a separate bug that will still need a fix after #4405 is merged.[JS/TS] Fix `static val mutable` fields declared with `[<DefaultValue…