Skip to content

[JS] Rework how we handle static field on class #4419

Description

@MangelMaxime

static fields in JavaScript are now globally available since 2021 and since 2019 in Node.js V12.

The following F# code

type ClassWithExplicitStaticFields() =
    static let mutable count = 42

    static member Count = count

generates

export class ClassWithExplicitStaticFields {
    constructor() {
    }
}

(() => {
    ClassWithExplicitStaticFields.count = 42;
})();

We could instead generate:

export class ClassWithExplicitStaticFields {
	static count = 42;
    constructor() {
    }
}

Activity

  1. github-actions commented on Mar 28, 2026

    @github-actions
    Contributor

    🤖 This is an automated response from Repo Assist.

    Great proposal! I had a look at the existing infrastructure — it's closer to ready than it might seem.

    Existing building blocks

    ClassProperty with isStatic: bool already exists in the Babel AST (src/Fable.Transforms/Global/Babel.fs), and ClassMember.classProperty is already used for TypeScript class property declarations (e.g. for [(DefaultValue)] fields in declareDefaultValueStaticFieldInits). So the AST and printer already support native static class fields.

    Where the IIFE currently comes from

    static let bindings in F# are compiled by FCS into a class static constructor (.cctor). Fable emits the .cctor body as an ActionDeclaration immediately after the class declaration, which then becomes an IIFE in the JS output. The class body itself doesn't see the static initializer at all — it arrives as a separate top-level declaration.

    Key technical consideration

    Native static field = value runs when the class expression is evaluated (i.e. when the module is first imported), not after the full module has been initialised. For simple literal values (static let count = 42) this is always safe. For initializers that reference other module-level bindings (static let items = ResizeArray(), static let logger = createLogger()) it may also be safe, but for ones that refer to values declared after the class in the source, the IIFE pattern provides a guarantee the native field initializer does not.

    Suggested implementation path

    1. In FSharp2Fable.fs, identify when a .cctor action contains only simple assignments to one class's static fields (i.e. no cross-class or cross-module dependencies).
    2. Tag those ActionDeclarations (or the corresponding MemberDecls) so Fable2Babel.fs can recognise them.
    3. In Fable2Babel.fs, instead of emitting those as an IIFE after the class, fold them into the class body as ClassMember.classProperty with isStatic = true.
    4. For initializers that can't be safely inlined (complex expressions with potential order-of-init dependencies), keep the IIFE as a fallback.

    A simpler first cut could handle only the [(DefaultValue)] path (which declareDefaultValueStaticFieldInits already handles) and the literal-initializer .cctor case.

    Note

    🔒 Integrity filtering filtered 58 items

    Integrity filtering activated and filtered the following items during workflow execution.
    This happens when a tool call accesses a resource that does not meet the required integrity or secrecy level of the workflow.

    • #4454 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #4393 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #4220 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #4166 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #4143 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #4104 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #4044 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #4038 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #3290 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #2279 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • #2154 (list_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • issue:[Feature] Array2D operations #1764 (list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • issue:DateTime.ParseExact breaks REPL #2003 (list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • issue:Is there a way to get attributes on a union case? #2026 (list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • issue:Reflection for classes #2027 (list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • issue:StackOverflowException when compiling large match expression #2039 (list_issues: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".)
    • ... and 42 more items

    Generated by Repo Assist · ◷

    To install this agentic workflow, run

    gh aw add githubnext/agentics/workflows/repo-assist.md@346204513ecfa08b81566450d7d599556807389f
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions