Scala.js:fastOptJS运行正常但fullOptJS失败,求助排查UndefinedBehaviorError
Hey, this is a super common gotcha with Scala.js builds—fastOptJS keeps things loose for debugging, while fullOptJS cranks up optimization and type strictness to 11. Let's break down why your code is breaking, then fix it.
The Root Cause
- fastOptJS is your debug-friendly build: it preserves runtime type checks and takes a lenient approach to type casts. When you use
asInstanceOf[Boolean]on a dynamic JS value (like theinputfrom swal), it might just return a wonky value instead of throwing an error, letting your code limp along. - fullOptJS is your production-ready build: it does aggressive optimizations like inlining functions, stripping dead code, and enforcing strict type assumptions. When you use
asInstanceOf[Boolean]on a value that's actually a string (which happens when the user enters text and confirms), Scala.js throwsUndefinedBehaviorErrorbecause it expects the type to match exactly in optimized mode.
Looking at your code, the input parameter from swal's callback is dynamically typed in JS: it's false (a boolean) when the user cancels, and a string when they enter text. Your direct asInstanceOf[Boolean] works in fastOpt because it's not checking strictly, but fullOpt calls you out on the type mismatch.
Fixes: Safely Handle Dynamic JS Values
Stop relying on asInstanceOf for cross-type casts on JS values. Instead, use Scala.js tools to check types properly.
Option 1: Check Types with js.typeOf
This mirrors JS's own type checking directly:
$("button").on("click", ".showDialog", (event: JQueryEventObject) => { event.preventDefault() val helpText = "Enter any number" js.Dynamic.global.swal( js.Dynamic.literal( title = helpText, text = helpText, `type` = "input", showCancelButton = true, closeOnConfirm = false, inputPlaceholder = helpText ), (input: js.Any) => { js.typeOf(input) match { case "boolean" => // User clicked cancel—input is false js.Dynamic.global.swal("Cancelled", "You bailed out!", "info") case "string" => // User entered text—parse it safely input.asInstanceOf[String].toIntOption match { case Some(validNum) => js.Dynamic.global.swal("Success!", s"Got your number: $validNum", "success") case None => js.Dynamic.global.swal("Oops!", "That's not a valid number", "error") } case _ => js.Dynamic.global.swal("Error!", "Unexpected input type", "error") } } ) })
Option 2: Scala-Style Pattern Matching
Scala.js lets you pattern match on JS values, making the code cleaner and more idiomatic:
(input: js.Any) => input match { case false: Boolean => // Handle cancel action js.Dynamic.global.swal("Cancelled", "Operation cancelled", "info") case inputStr: String if inputStr.trim.nonEmpty => // Process the input string inputStr.toIntOption match { case Some(num) => js.Dynamic.global.swal("Great!", s"Number received: $num", "success") case None => js.Dynamic.global.swal("Whoops!", "Please enter a valid number", "error") } case _ => // Catch-all for empty input or weird types js.Dynamic.global.swal("Error!", "Something went wrong", "error") }
Pro Tip: Ditch Any for js.Any
Change your callback parameter type from Any to js.Any (or js.Dynamic). This tells Scala.js you're dealing with a native JS value, so type checks and conversions will behave as expected, rather than treating it like a Scala Any type.
How to Verify
After updating your code, run fullOptJS and test the production build. If you still hit issues, you can enable debug mode for fullOpt with the -P scalajs:devMode flag—this keeps more debug info around to help track down any remaining problems.
内容的提问来源于stack exchange,提问作者sergeda

