diff --git a/src/Fable.Core/Fable.Core.Types.fs b/src/Fable.Core/Fable.Core.Types.fs
index 1641884a0..7c255439c 100644
--- a/src/Fable.Core/Fable.Core.Types.fs
+++ b/src/Fable.Core/Fable.Core.Types.fs
@@ -96,8 +96,24 @@ type EmitIndexerAttribute() =
type EmitPropertyAttribute(propertyName: string) =
inherit Attribute()
+///
/// Compile union types as string literals.
-/// More info: https://fable.io/docs/communicate/js-from-fable.html#stringenum-attribute
+///
+///
+/// You can also use [<CompiledName>] and [<CompiledValue>] to
+/// specify the name or literal of the union case in the generated code:
+///
+/// [<StringEnum>]
+/// type EventType =
+/// | [<CompiledName("Abracadabra")>] MouseOver
+/// | [<CompiledValue(false)>] RealMagic
+/// let eventType = EventType.MouseOver // Compiles: "Abracadabra"
+/// let magicPower = EventType.RealMagic // Compiles: false
+///
+///
+///
+/// Fable Documentation
+///
[]
type StringEnumAttribute(caseRules: CaseRules) =
inherit Attribute()
diff --git a/src/Fable.Transforms/FSharp2Fable.Util.fs b/src/Fable.Transforms/FSharp2Fable.Util.fs
index ed0e795be..523b3ae5a 100644
--- a/src/Fable.Transforms/FSharp2Fable.Util.fs
+++ b/src/Fable.Transforms/FSharp2Fable.Util.fs
@@ -937,12 +937,14 @@ module Helpers =
with _ ->
failwith $"Cannot find case %s{unionCase.Name} in %s{FsEnt.FullName ent}"
- /// Apply case rules to case name if there's no explicit compiled name
+ /// Apply case rules to case name if there's no explicit compiled name or compiled value
let transformStringEnum (rule: CaseRules) (unionCase: FSharpUnionCase) =
- match FsUnionCase.CompiledName unionCase with
- | Some name -> name
- | None -> Naming.applyCaseRule rule unionCase.Name
- |> makeStrConst
+ match FsUnionCase.CompiledName unionCase, FsUnionCase.CompiledValue unionCase with
+ | Some name, _ -> name |> makeStrConst
+ | _, Some(CompiledValue.Boolean value) -> makeBoolConst value
+ | _, Some(CompiledValue.Float value) -> makeFloatConst value
+ | _, Some(CompiledValue.Integer value) -> makeIntConst value
+ | _ -> Naming.applyCaseRule rule unionCase.Name |> makeStrConst
// let isModuleMember (memb: FSharpMemberOrFunctionOrValue) =
// match memb.DeclaringEntity with
diff --git a/tests/Js/Main/JsInteropTests.fs b/tests/Js/Main/JsInteropTests.fs
index b44ad5c69..c0461d7c8 100644
--- a/tests/Js/Main/JsInteropTests.fs
+++ b/tests/Js/Main/JsInteropTests.fs
@@ -225,6 +225,18 @@ type LowerAllOptions =
| ContentBox
| BorderBox
+type RespectValuesEnum = Foo = 0 | Bar = 1 | Baz = 2
+
+[]
+type RespectValues =
+ | ContentBox
+ | [] None
+ | [] AnswerToLife
+ | [] Pi
+ | [] Foo
+ | [] Bar
+// | [] Undefined // Error: Expected: undefined - Actual: undefined
+
[]
#endif
type Field = OldPassword | NewPassword | ConfirmPassword
@@ -829,6 +841,20 @@ let tests =
let x = LowerAllOptions.ContentBox
x |> unbox |> equal "contentbox"
+ testCase "StringEnum is overwritten by CompiledValue" <| fun () ->
+ RespectValues.ContentBox |> unbox |> equal "contentbox"
+ RespectValues.None |> unbox |> equal false
+ // When running fable-compiler-js we can't make a distinction between int and float at runtime
+ // See https://github.com/fable-compiler/Fable/pull/4144#issuecomment-3001681838
+ #if !NPM_PACKAGE_FABLE_COMPILER_JAVASCRIPT
+ RespectValues.Pi |> unbox |> equal 3.14159
+ #endif
+ RespectValues.AnswerToLife |> unbox |> equal 42
+ RespectValues.Foo |> unbox |> equal RespectValuesEnum.Foo
+
+ testCase "StringEnum CompiledName over CompiledValue" <| fun () ->
+ RespectValues.Bar |> unbox |> equal "Bar"
+
// See https://github.com/fable-compiler/fable-import/issues/72
testCase "Can use values and functions from global modules" <| fun () ->
GlobalModule.add 3 4 |> equal 7