Skip to content

BridgeJS: Support a jsName override for exported @JS declarations #788

Description

@krodak

Overview

The export @JS macro derives the JavaScript-facing name of an exported declaration from its Swift declaration name. There is currently no way to override it — unlike the import macros (@JSGetter, @JSSetter, @JSFunction), which already accept a jsName: parameter.

This means the Swift symbol name is forced to equal the desired JS name. When the desired JS name collides with something already in scope in the Swift module — most commonly an imported module of the same name, or another top-level symbol — you're forced to either rename the JS-facing API (changing the consumer surface) or introduce a workaround (e.g. a small shim module that re-exports the shadowed type under an alias) purely to escape the shadow.

A jsName: override on the export macro would let the exported JS name be decoupled from the Swift declaration name, matching the ergonomics the import macros already have.

Proposal

Add an optional jsName: String? = nil (name TBD — could also be name:) to the export @JS macro:

public macro JS(
    as aliasOf: Any.Type? = nil,
    namespace: String? = nil,
    jsName: String? = nil,
    enumStyle: JSEnumStyle = .const,
    identityMode: Bool = false
) = Builtin.ExternalMacro

When present, jsName sets the exported leaf name; when absent, behavior is unchanged (Swift declaration name is used).

Example

Say a module imports a dependency module named Foo and also wants to export a class to JS as Foo. Today the Swift class must be named Foo, which shadows the imported Foo module module-wide, making the upstream Foo.Bar type unreachable without a workaround. With jsName:

import Foo

@JS(namespace: "MyApp", jsName: "Foo")
final class MyAppFoo {
    // free to reference the imported `Foo` module here — no shadow
}

JavaScript sees MyApp.Foo; the Swift symbol stays MyAppFoo.

Scope

  • Export macro only (classes, structs, enums, functions).
  • TS .d.ts and JS glue names should follow jsName.
  • Interaction with namespace: should compose (namespace prefix + jsName leaf).
  • Diagnostic if jsName is empty/invalid as a JS identifier.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions