MoonBit <-> JavaScript value conversion (Map/Json/Option/Result <-> Any) and runtime type inspection
Dependencies
| MoonBit | JavaScript |
|---|---|
| Some(42) | 42 |
| None | undefined |
let some_val : Int? = Some(42)
let js_val = @core.any(some_val) // JS: 42
let none_val : Int? = None
let js_val = @core.any(none_val) // JS: undefined| MoonBit | JavaScript | constructor.name |
|---|---|---|
| Ok(42) | { _0: 42 } | "Result$Ok$N$" |
| Err("error") | { _0: "error" } | "Result$Err$N$" |
// Use constructor name
const isOk = value.constructor.name.includes("Ok")
const isErr = value.constructor.name.includes("Err")
// Or use js_convert utilities from MoonBit
let is_ok = @convert.is_result_ok(js_val)
let is_err = @convert.is_result_err(js_val)enum Color { Red, Green, Blue }
let red = Red // JS: { $tag: 0, $name: "Red" }enum Color { Rgb(Int, Int, Int) }
let rgb = Rgb(255, 0, 0) // JS: { $tag: 3, _0: 255, _1: 0, _2: 0 }
// constructor.name: "Color$Rgb"enum Shape { Circle(~radius: Int) }
let c = Circle(radius=10) // JS: { $tag: 0, radius: 10 }struct Point { x: Int, y: Int }
let p = Point::{ x: 10, y: 20 } // JS: { x: 10, y: 20 }// Convert Map to JS object
let obj = @convert.from_map({
"name": @core.any("Alice"),
"age": @core.any(30)
})
// JavaScript: { name: "Alice", age: 30 }
// Convert Map with optional values (skips None)
let obj = @convert.from_option_map({
"name": Some(@core.any("Bob")),
"email": None, // Skipped
"age": Some(@core.any(25))
})
// JavaScript: { name: "Bob", age: 25 }
// Returns undefined if all values are None
let result = @convert.from_option_map_or_undefined({
"timeout": None,
"retries": None
})
// JavaScript: undefined// Convert MoonBit Json to JS value
let json : Json = { "name": "Alice", "age": 30 }
let js_obj = @convert.from_json(json)
// Convert JS value to MoonBit Json
let js_obj = @core.any({ "name": "Alice" })
let json = @convert.to_json(js_obj)// Convert Option to @core.Any (None becomes null)
let some_val : @core.Any? = Some(@core.any(42))
let result = @convert.from_option(some_val) // 42
let none_val : @core.Any? = None
let result = @convert.from_option(none_val) // null
// Convert @core.Any to Option (null/undefined becomes None)
let val = @core.any(123)
let opt : Int? = @convert.to_option(val) // Some(123)
let null_val = @core.null()
let opt : Int? = @convert.to_option(@core.any(null_val)) // None// Check if Result is Ok or Err
let ok_result : Result[Int, String] = Ok(42)
let is_ok = @convert.is_result_ok(@core.any(ok_result)) // true
let is_err = @convert.is_result_err(@core.any(ok_result)) // false
// Unwrap values
let value : Int = @convert.unwrap_ok(@core.any(ok_result)) // 42
let err_result : Result[Int, String] = Err("error")
let error : String = @convert.unwrap_err(@core.any(err_result)) // "error"
// Convert back to MoonBit Result
let js_val = @core.any(ok_result)
let back : Result[Int, String] = @convert.to_result(js_val) // Ok(42)enum Color { Red, Green, Blue, Rgb(Int, Int, Int) }
// Get variant name
let name = @convert.get_enum_variant_name(@core.any(Red)) // "Red"
let name = @convert.get_enum_variant_name(@core.any(Rgb(255, 0, 0))) // "Rgb"
// Get tag index
let tag = @convert.get_enum_tag(@core.any(Red)) // 0
let tag = @convert.get_enum_tag(@core.any(Rgb(255, 0, 0))) // 3// JavaScript side
function handleMoonBitResult(result) {
if (result.constructor.name.includes("Ok")) {
return { success: true, value: result._0 };
} else {
return { success: false, error: result._0 };
}
}import {
isOk, isErr, unwrapOk, matchResult,
isSome, isNone, unwrapOr,
getVariantName, getEnumTag, getTupleArgs,
} from "./src/types.ts";import { isOk, isErr, unwrapOk, matchResult, toResultObject } from "./types.ts";
// Type-safe Result handling
const result = mbtFunction(); // Returns MoonBit Result
if (isOk(result)) {
console.log("Success:", result._0);
} else {
console.log("Error:", result._0);
}
// Pattern matching
const message = matchResult(result, {
ok: (value) => `Got value: ${value}`,
err: (error) => `Error: ${error}`,
});
// Convert to plain object (for serialization)
const obj = toResultObject(result);
// { type: "ok", value: 42 } or { type: "err", error: "..." }import { isSome, isNone, unwrapOr } from "./types.ts";
const option = mbtFunction(); // Returns MoonBit Option (T | undefined)
if (isSome(option)) {
console.log("Value:", option);
}
// With default value
const value = unwrapOr(option, 0);import { isUnitVariant, getVariantName, getEnumTag, getTupleArgs } from "./types.ts";
const color = mbtFunction(); // Returns MoonBit enum
// Get variant name
const name = getVariantName(color); // "Red" or "Rgb"
// Get tag index
const tag = getEnumTag(color); // 0, 1, 2, ...
// For tuple variants, get arguments
if (!isUnitVariant(color)) {
const args = getTupleArgs(color); // [255, 128, 64]
}import { serializeResult, deserializeResult } from "./types.ts";
// Result loses Ok/Err distinction in JSON
// Use these helpers to preserve it:
const result = mbtFunction();
const serialized = serializeResult(result);
// { _type: "Ok", _0: 42 }
const json = JSON.stringify(serialized);
// Can be safely transmitted/stored
const parsed = JSON.parse(json);
const restored = deserializeResult(parsed);
// { type: "ok", value: 42 }import {
serializeResult,
restoreResult,
isOk,
unwrapOk,
createOk,
createErr,
} from "./types.ts";
// Serialize from MoonBit
const result = mbtFunction();
const serialized = serializeResult(result);
const json = JSON.stringify(serialized);
// Later: restore with prototype
const parsed = JSON.parse(json);
const restored = restoreResult<number, string>(parsed);
// Now isOk/isErr work again!
if (isOk(restored)) {
console.log(unwrapOk(restored));
}
// Or create new Result values from TypeScript
const ok = createOk(42); // Works with isOk()
const err = createErr("msg"); // Works with isErr()import { restoreEnum, createEnumTuple, getEnumTag, getVariantName } from "./types.ts";
// Restore from serialized form
const serialized = '{"_tag":3,"_name":"Rgb","_args":[255,128,64]}';
const color = restoreEnum(JSON.parse(serialized), "Color");
getEnumTag(color); // 3
getVariantName(color); // "Rgb"
// Or create directly
const rgb = createEnumTuple("Color", "Rgb", 3, [255, 128, 64]);// Result type
type MbtResult<T, E> = MbtResultOk<T> | MbtResultErr<E>;
// Option type (MoonBit unwraps Some)
type MbtOption<T> = T | undefined;
// Enum unit variant
interface MbtEnumUnit {
$tag: number;
$name: string;
}
// Enum tuple variant
interface MbtEnumTuple {
_0?: unknown;
_1?: unknown;
// ...
}
// Trait object
interface MbtTraitObject<T> {
self: T;
method_0: Function;
// ...
}| Type | JSON Safe | Notes |
|---|---|---|
| Primitives | ✅ | Fully preserved |
| Array | ✅ | Fully preserved |
| Struct | ✅ | Field names preserved |
| Enum (unit) | ✅ | $tag and $name preserved |
| Enum (tuple) | ⚠️ | $tag LOST in JSON |
| Enum (labeled) | ❌ | Labels become _0, _1... |
| Result | ❌ | Ok/Err distinction LOST |
| Option None | ⚠️ | Becomes null/undefined |
| BigInt | ❌ | JSON.stringify throws |
| Map | ❌ | Internal structure |
| Function | ❌ | Not serializable |
let serialized = json_parse("{\"_some\":true,\"_0\":42}")
let opt : Int? = @convert.deserialize_option(serialized)let serialized = json_parse("{\"_tag\":\"Ok\",\"_0\":42}")
let result : Result[Int, String] = @convert.deserialize_result(serialized)// Convert MoonBit Json to JS
let json : Json = { "name": "Alice", "age": 30 }
let js_obj = @convert.from_json(json)let obj = @convert.from_map({ "name": @core.any("Alice"), "age": @core.any(30) })
// JavaScript: { name: "Alice", age: 30 }let _obj = @convert.from_option_map({
"name": Some(@core.any("Alice")),
"age": Some(@core.any(30)),
"email": None,
})
// JavaScript: { name: "Alice", age: 30 }// All None - returns undefined
let result = @convert.from_option_map_or_undefined({
"timeout": None,
"retries": None,
})
// JavaScript: undefined
// Some values - returns object
let result = @convert.from_option_map_or_undefined({
"timeout": Some(@core.any(5000)),
"retries": None,
})
// JavaScript: { timeout: 5000 }// For unit variant: returns "Red"
// For tuple variant: returns "Rgb" (parsed from "Color$Rgb")let err_result : Result[Int, String] = Err("error")
let is_err = @convert.is_result_err(@core.any(err_result)) // truelet ok_result : Result[Int, String] = Ok(42)
let is_ok = @convert.is_result_ok(@core.any(ok_result)) // truelet some_val : Int? = Some(42)
let serialized = @convert.serialize_option(some_val)
// JavaScript: { "_some": true, "_0": 42 }let result : Result[Int, String] = Ok(42)
let serialized = @convert.serialize_result(result)
// JavaScript: { "_tag": "Ok", "_0": 42 }let js_obj = @core.any({ "name": "Alice" })
let json = @convert.to_json(js_obj)let ok_result : Result[Int, String] = Ok(42)
let js_val = @core.any(ok_result)
let back : Result[Int, String] = @convert.to_result(js_val)let err_result : Result[Int, String] = Err("error")
let error : String = @convert.unwrap_err(@core.any(err_result)) // "error"Install
Download zipMoonBit <-> JavaScript value conversion (Map/Json/Option/Result <-> Any) and runtime type inspection
Dependencies