diff --git a/src/Fable.Cli/CHANGELOG.md b/src/Fable.Cli/CHANGELOG.md index 4800123479..30625baab7 100644 --- a/src/Fable.Cli/CHANGELOG.md +++ b/src/Fable.Cli/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [JS/TS] Fix escaping of `{` and `}` in FormattableString (#3890) (by @roboz0r) * [JS/TS] Fix `uri.Host` to return the host name without the port (by @MangelMaxime) +* [JS/TS] Fix TypeScript compilation by resolving type of `jsOptions` (#3894) (by @ManngelMaxime) ## 4.20.0 - 2024-09-04 diff --git a/src/Fable.Transforms/Replacements.fs b/src/Fable.Transforms/Replacements.fs index f142108bfb..0360b27c3a 100644 --- a/src/Fable.Transforms/Replacements.fs +++ b/src/Fable.Transforms/Replacements.fs @@ -713,12 +713,17 @@ let makeGenericAverager (com: ICompiler) ctx t = "DivideByInt", divideFn ] -let makePojoFromLambda com arg = +let makePojoFromLambda com (arg: Expr) = let rec flattenSequential = function | Sequential statements -> List.collect flattenSequential statements | e -> [ e ] + let typ, genArgs = + match arg.Type with + | LambdaType(argType, _) -> argType, Some [ argType ] + | _ -> Any, None + match arg with | Lambda(_, lambdaBody, _) -> (flattenSequential lambdaBody, Some []) @@ -728,8 +733,8 @@ let makePojoFromLambda com arg = | _ -> None ) | _ -> None - |> Option.map (fun members -> ObjectExpr(members, Any, None)) - |> Option.defaultWith (fun () -> Helper.LibCall(com, "Util", "jsOptions", Any, [ arg ])) + |> Option.map (fun members -> ObjectExpr(members, typ, None)) + |> Option.defaultWith (fun () -> Helper.LibCall(com, "Util", "jsOptions", typ, [ arg ], ?genArgs = genArgs)) let makePojo (com: Compiler) caseRule keyValueList = let makeObjMember caseRule name values = diff --git a/src/fable-library-ts/CHANGELOG.md b/src/fable-library-ts/CHANGELOG.md index af01b53de6..e0055a06c8 100644 --- a/src/fable-library-ts/CHANGELOG.md +++ b/src/fable-library-ts/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * [JS/TS] Fix escaping of `{` and `}` in FormattableString (#3890) (by @roboz0r) * [JS/TS] Fix `uri.Host` to return the host name without the port (by @MangelMaxime) +* [JS/TS] Fix TypeScript compilation by resolving type of `jsOptions` (#3894) (by @ManngelMaxime) ## 1.4.3 - 2024-09-04 diff --git a/src/fable-library-ts/Util.ts b/src/fable-library-ts/Util.ts index c6c2d14191..8d1bfa0293 100644 --- a/src/fable-library-ts/Util.ts +++ b/src/fable-library-ts/Util.ts @@ -588,8 +588,8 @@ export function createObj(fields: Iterable<[string, any]>) { return obj; } -export function jsOptions(mutator: (x: object) => void): object { - const opts = {}; +export function jsOptions(mutator: (x: T) => void): T { + const opts = {} as T; mutator(opts); return opts; } diff --git a/tests/Js/Main/JsInteropTests.fs b/tests/Js/Main/JsInteropTests.fs index 349ba81e86..82d9f40b37 100644 --- a/tests/Js/Main/JsInteropTests.fs +++ b/tests/Js/Main/JsInteropTests.fs @@ -741,6 +741,16 @@ let tests = opts.foo |> equal "bar" opts.bar |> equal 5 + testCase "jsOptions works when it is directly replaced as a POJO" <| fun () -> + let opts = jsOptions(fun o -> + // This function call avoid the optimization to literal POJO + let foo () = "foo" + o.foo <- foo() + o.bar <- 5 + ) + opts.foo |> equal "foo" + opts.bar |> equal 5 + testCase "Stringifying a JS object works" <| fun () -> let fooOptional = importMember "./js/1foo.js" string fooOptional |> equal "much foo, much awesome" diff --git a/tests/TypeScript/Fable.Tests.TypeScript.fsproj b/tests/TypeScript/Fable.Tests.TypeScript.fsproj index 3e237355bb..2e064df078 100644 --- a/tests/TypeScript/Fable.Tests.TypeScript.fsproj +++ b/tests/TypeScript/Fable.Tests.TypeScript.fsproj @@ -46,6 +46,7 @@ + diff --git a/tests/TypeScript/LiteTsInteropTests.fs b/tests/TypeScript/LiteTsInteropTests.fs new file mode 100644 index 0000000000..83cc534a76 --- /dev/null +++ b/tests/TypeScript/LiteTsInteropTests.fs @@ -0,0 +1,37 @@ +module Fable.Tests.LiteTsInterop + +open System +open Util.Testing +open Fable.Core + +#if FABLE_COMPILER +open Fable.Core.JsInterop +open Fable.Core.DynamicExtensions +open Fable.Core.Experimental +#endif + +type JsOptions = + abstract foo: string with get, set + abstract bar: int with get, set +let tests = + testList "LiteTsInterop" [ + #if FABLE_COMPILER + testCase "jsOptions works" <| fun _ -> + let opts = jsOptions(fun o -> + o.foo <- "bar" + o.bar <- 5 + ) + opts.foo |> equal "bar" + opts.bar |> equal 5 + + testCase "jsOptions works when it is directly replaced as a POJO" <| fun () -> + let opts = jsOptions(fun o -> + // This function call avoid the optimization to literal POJO + let foo () = "foo" + o.foo <- foo() + o.bar <- 5 + ) + opts.foo |> equal "foo" + opts.bar |> equal 5 + #endif + ] diff --git a/tests/TypeScript/Main.fs b/tests/TypeScript/Main.fs index 45658b58da..3419067842 100644 --- a/tests/TypeScript/Main.fs +++ b/tests/TypeScript/Main.fs @@ -28,6 +28,7 @@ let allTests = HashSets.tests // Import.tests // JsInterop.tests + LiteTsInterop.tests Lists.tests Maps.tests Misc.tests