Bidirectional type definition converter between MoonBit and TypeScript.
deno install -Afg @mizchi/mbts --name mbts
# TODO: npm- Create new MoonBit projects with JS interop setup
- Full build pipeline (check, build, link, dts)
.mbti→.d.tsgeneration.d.ts→.mbt/.mbtigeneration- Auto-update
moon.pkg.jsonexports
# As a CLI tool
pnpm add mbts
# Or use directly
npx mbts --help# Create a new project
mbts new myapp --user myname
cd myapp
moon update
# Build and generate TypeScript definitions
mbts build .
# Use from JavaScript
node -e "const m = require('./target/js/release/build/myapp/myapp.js'); console.log(m.hello())"mbts new <pkgname> --user <username>Creates a new MoonBit project with:
moon.mod.json- Module config withmizchi/jsdependency andpreferred-target: jsmoon.pkg.json- Package config with JS link settingslib.mbt- Sample source file
# Create project
mbts new myapp --user myname
# Without --user (uses "username" as default with warning)
mbts new myappmbts build <path>Runs the complete build pipeline:
moon check- Type checkingmoon build --target js- Build for JS targetmoon info- Generate .mbtimbts link- Update exports in moon.pkg.jsonmbts dts- Generate .d.ts
# Build current directory
mbts build .
# Build specific directory
mbts build examples
# With options
mbts build . --out js --naming camelCasembts link <path>Updates moon.pkg.json with exports from .mbti file. Also generates __jsglue.mbt for generic function wrappers.
# Update exports after running 'moon info'
moon info
mbts link .
# Multiple targets
mbts link . --targets js,wasm-gc
# Exclude methods
mbts link . --no-methods
# Dry run
mbts link . --dry-runmbts dts <src> [--out <dir>]Generates .d.ts from .mbti file.
# Generate .d.ts in same directory
mbts dts .
# Output to different directory
mbts dts src --out js
# Wrap in namespace
mbts dts src --namespace
# Include runtime type preamble
mbts dts src --preamble
# Convert function names to camelCase
mbts dts src --naming camelCasembts mbt <file.d.ts> [options]Generates MoonBit FFI bindings from TypeScript definitions.
# Basic conversion
mbts mbt lib.d.ts
# Specify output directory and package name
mbts mbt lib.d.ts --out src --package myapp
# Also generate .mbti interface file
mbts mbt lib.d.ts --mbti| MoonBit | TypeScript |
|---|---|
String |
string |
Int, UInt, Float, Double |
number |
Bool |
boolean |
Unit |
void |
Bytes |
Uint8Array |
BigInt |
bigint |
Array[T] |
Array<T> |
Map[K, V] |
Map<K, V> |
Json |
any |
T? / Option[T] |
T | undefined |
(A, B, C) |
[A, B, C] |
| TypeScript | MoonBit |
|---|---|
string |
String |
number |
Int |
boolean |
Bool |
void |
Unit |
Uint8Array |
Bytes |
bigint |
BigInt |
T[] / Array<T> |
Array[T] |
Map<K, V> |
@collection.JsMap[K, V] |
Set<T> |
@collection.JsSet[T] |
Promise<T> |
@js.Promise[T] |
T | undefined |
T? |
any / unknown |
Json |
// MoonBit
pub struct User {
name : String
age : Int
mut email : String
}// TypeScript
export interface User {
readonly name: string;
readonly age: number;
email: string;
}// MoonBit
pub enum Status {
Pending
Active
Done
}// TypeScript (Discriminated Union)
export interface Status_Pending { readonly $tag: "Pending"; }
export interface Status_Active { readonly $tag: "Active"; }
export interface Status_Done { readonly $tag: "Done"; }
export type Status = Status_Pending | Status_Active | Status_Done;// MoonBit - Generic function (needs wrapper for JS export)
pub fn[T] identity(value : T) -> T {
value
}
// FFI functions must use @js.Any (no type parameters allowed)
extern "js" fn Box::new(value : @js.Any) -> Box[@js.Any] =
#| (v) => ({ value: v })When you run mbts link, it automatically generates wrappers in __jsglue.mbt:
// Auto-generated
pub fn __jsglue_identity(arg0 : @js.Any) -> @js.Any {
identity(arg0)
}| MoonBit | TypeScript (default) | TypeScript (--naming camelCase) |
|---|---|---|
get_user_name |
get_user_name |
getUserName |
Type::method |
type$method |
type$method |
pub struct User {
id : Int // immutable
mut name : String // mutable
}export interface User {
readonly id: number; // readonly (immutable)
name: string; // writable (mut)
}pub enum Result[T, E] {
Ok(T)
Err(E)
}export interface Result_Ok<T> { readonly $tag: "Ok"; readonly $0: T; }
export interface Result_Err<E> { readonly $tag: "Err"; readonly $0: E; }
export type Result<T, E> = Result_Ok<T> | Result_Err<E>;pub fn find(id : Int) -> User?export function find(id: number): User | undefined;pub fn get_pair() -> (Int, String)export function get_pair(): [number, string];Methods are exported with $ separator:
pub fn User::new(name : String) -> User
pub fn User::greet(self : User) -> Stringexport function user$new(name: string): User;
export function user$greet(self: User): string;import { generateDts } from "mbts";
const mbtiContent = `
package "myapp"
pub struct User {
name : String
age : Int
}
pub fn get_user(id : Int) -> User
`;
const dts = generateDts(mbtiContent, "myapp.mbti");import { parseDts, generateMbt, generateMbti } from "mbts";
const dtsContent = `
export interface User {
name: string;
age: number;
}
export function createUser(name: string): User;
`;
const binding = parseDts(dtsContent, "lib.d.ts", { packageName: "myapp" });
const mbt = generateMbt(binding);
const mbti = generateMbti(binding);extern "js" fncannot have type parameters - Use@js.Anyinstead- Generic functions need wrappers for JS export -
mbts linkgenerates these automatically - Always run
moon infobeforembts link/dts- The.mbtifile must be up to date - Set
preferred-target: jsinmoon.mod.jsonfor JS-only projects
# Install dependencies
moon update
pnpm install
# Build CLI
pnpm build:cli
# Run tests
moon test
pnpm testmbts uses an internal .mbti parser to analyze MoonBit's interface files. The parser extracts:
- Function signatures with type parameters
- Struct and enum definitions
- Method declarations
For generic functions that cannot be directly exported to JavaScript (due to MoonBit's FFI limitation), mbts automatically generates wrapper functions in __jsglue.mbt. These wrappers replace type parameters with @js.Any, enabling JavaScript interop while preserving the original generic implementation.
.mbti (parsed) → AST → analyze generics → generate __jsglue.mbt
MIT