TypeMojo is a Mojo-to-TypeScript transpiler for people who want more than a parser demo.
It takes a large, practical subset of Mojo and lowers it to runnable ESM TypeScript with a real proof harness behind it: transpilation, strict typechecking, execution, audits, and a separate native-Mojo validation lane. It is not a full Mojo compiler, and it does not pretend otherwise.
Mojo has interesting language ideas. TypeScript has a huge tooling ecosystem. TypeMojo explores the overlap seriously:
- Mojo syntax and structure as source language.
- TypeScript,
ts-morph, and compiler APIs as the target playground. - End-to-end examples as the source of truth, not aspirational feature lists.
The goal is not "compile everything." The goal is "transpile a meaningful subset well, honestly, and with proof."
| Lane | Status | What It Means |
|---|---|---|
| Transpiler corpus | 100/100 green |
100 runnable programs transpile, typecheck, and execute |
| Native Mojo lane | 14/14 green |
Curated Mojo-native programs run under local mojo 24.4.0 |
| Strict TS audit | green | Generated TypeScript has 0 strict diagnostics in the current audit |
| Broader Mojo compatibility | tracked separately | The full transpiler corpus is not claimed to be native-Mojo runnable |
Current corpus breakdown:
16fixtures7benchmarks77TypeScript / compiler /ts-morphexamples
Catalog source of truth:
Native Mojo source of truth:
- Lowering
fnanddefto typed TypeScript functions - Lowering
structto classes andtraitto interfaces - Mapping Mojo containers onto JS-native targets:
List[T] -> T[],Dict[K, V] -> Map<K, V],Set[T] -> Set<T> - Rewriting common built-ins and methods:
print,len,range,zip,enumerate,append,items(), slicing, and string formatting - Handling async functions, generators, tuple unpacking, comprehensions,
match, imports, andtry/except - Emitting importable modules with guarded
main()entrypoints - Exercising TS-native concepts through real examples:
package imports, namespace imports, factory/printer APIs,
ts-morphproject traversal, checker queries, refactor previews
Some Mojo semantics do not have a faithful TS equivalent today. TypeMojo tracks those explicitly.
Current lossy areas include:
- Ownership conventions like
owned,borrowed,mut,ref,out,inout - Transfer expressions like
value^ - Marker traits like
CopyableandEquatable - Compile-time parameters and compile-time call arguments
- Anything with no implemented lowering path yet
This is not hidden behind silent degradation.
AnyTypelowers to explicitUnsafeAny- strict mode rejects lossy transforms
- the audit reports where unsafe interop still exists
That design is intentional, and closer to the AssemblyScript philosophy than to a "shrug and emit any" transpiler.
bun install
# Transpile one file to stdout
bun run src/cli.ts input.mojo
# Write output to a file
bun run src/cli.ts input.mojo -o output.ts
# Transpile a directory
bun run src/cli.ts tests/fixtures -o out/
# Validate only
bun run src/cli.ts input.mojo --check
# Full transpiler proof lane
bun run scripts/e2e.ts
# Strict generated-TS audit
bun run scripts/example-audit.ts
# Curated native Mojo lane
bun run scripts/mojo-e2e.ts
# Broader native compatibility report
bun run scripts/mojo-compat-report.tsSource:
@value
struct Point:
var x: Float64
var y: Float64
fn distance(self) -> Float64:
return sqrt(self.x ** 2 + self.y ** 2)
def main():
var p = Point(3.0, 4.0)
print(p.distance())Output:
import { _print } from "./_typemojo_runtime";
export class Point {
x!: number;
y!: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
distance(): number {
return Math.sqrt(this.x ** 2 + this.y ** 2);
}
}
export function main() {
const p = new Point(3.0, 4.0);
_print(p.distance());
}TypeMojo is built around verification lanes, not optimistic docs.
- scripts/e2e.ts
- Transpiles the full corpus
- Typechecks generated TypeScript
- Executes every runnable program
- scripts/example-audit.ts
- Audits generated files with
ts-morph - Verifies declared TS-concept coverage against emitted code
- Writes the report to docs/example-audit.md
- scripts/mojo-e2e.ts
- Runs the curated native-Mojo catalog
- Enforces expected output
- Intended to stay
100%green
- scripts/mojo-compat-report.ts
- Runs the broader fixtures and benchmarks under Mojo
- Reports the gap honestly
- Does not pretend the full TS-interop corpus should execute unchanged under native Mojo
That split matters. A repo like this gets worse when "native Mojo support" and "transpiler support" are mixed into one dishonest number.
TypeMojo now has a dedicated typechecking environment for generated output:
This gives the generated TypeScript:
- strict compiler settings
- explicit ambient target types
- no silent implicit-
anyleakage - visible unsafe boundaries via
UnsafeAny
That is a better design than pretending JS/TS interop is always type-safe.
The 77 examples under examples/ are not filler. They are organized pressure tests for the lowering model.
Waves include:
- TypeScript compiler API scans: diagnostics, import graphs, switch audits, template literals, AST printers, namespace scans, JSX inventories, type-node scans
- Compiler API builders: enum emission, union builders, overload scanning, JSDoc analysis
ts-morphstructural examples: project traversal, class/interface/export/import inventories, heritage graphs, overload matrices, reference searchts-morphtype-system examples: mapped types, conditional types, literal types, tuple types, recursive types, call signatures, ambient declarations- Refactor and symbol examples: rename previews, symbol maps, binding-pattern scans, import-usage maps
See:
Common commands from package.json:
bun test
bun run scripts/e2e.ts
bun run scripts/example-audit.ts
bun run scripts/mojo-e2e.ts
bun run scripts/mojo-compat-report.ts
bun run scripts/bench.ts
bun run scripts/generate-tooling-examples.ts
bun run buildMojo source
-> Lexer
-> Parser
-> Analyzer
-> CodeGen
-> ESM TypeScript
Key files:
- src/lexer.ts: tokenization, including f-strings and multi-line handling
- src/parser.ts: recursive-descent parser with recovery
- src/analyzer.ts: lightweight semantic and type-hint pass
- src/codegen.ts: TS emission, runtime imports, lossy metadata
- src/runtime.ts: runtime helpers like
_print,range, slicing, and formatting - src/cli.ts: CLI and directory transpilation
Three rules drive the project:
- If a feature matters, it should appear in an executable example.
- If a transform is lossy, it should be visible and rejectable.
- If a number is quoted in the README, there should be a script that proves it.
That is the bar.