Skip to content

Latest commit

 

History

1,779 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoScript: a Go to TypeScript compiler

Your Go code runs anywhere TypeScript runs: Node, Bun, and the browser.

GoScript side-by-side Go source and generated TypeScript output showing a channel send, goroutine scheduling, and awaited channel receive.

Go Reference Ask DeepWiki

GoScript compiles Go packages into readable TypeScript modules. Goroutines, channels, select, defer, pointers, and struct copies behave as they do in Go, and the output is ordinary TypeScript you can import, bundle, and step through in a debugger.

go install github.com/s4wave/goscript/cmd/goscript@latest
goscript compile --package . --output ./output

Install

GoScript needs the Go toolchain. Install the CLI with Go:

go install github.com/s4wave/goscript/cmd/goscript@latest

Or add it to a JavaScript project. The npm package runs the same compiler through your local Go toolchain and adds the TypeScript API:

bun add -d goscript

Bun runs generated code directly. For Node and browsers, bundle it with a bundler that resolves tsconfig.json paths, such as Bun, Vite, or esbuild.

Quick Start

Write a Go program:

// main.go
package main

import "fmt"

type Greeter struct{ Name string }

func (g Greeter) Greet() string { return "Hello, " + g.Name + "!" }

func main() {
	ch := make(chan string)
	go func() { ch <- Greeter{Name: "GoScript"}.Greet() }()
	fmt.Println(<-ch)
}

Compile it from the module directory. GoScript also emits the packages it imports, here fmt, so the output runs on its own:

goscript compile --package . --output ./output

Point @goscript/* imports at the output in tsconfig.json:

{
  "compilerOptions": {
    "paths": { "@goscript/*": ["./output/@goscript/*"] }
  }
}

Run it:

$ bun run output/@goscript/example.com/hello/main.gs.ts
Hello, GoScript!

Each Go package becomes a directory under output/@goscript/, named by its import path, with one .gs.ts file per Go file and an index.ts that exports the package. A package main runs directly; any other package is a module you import:

import { NewUser } from '@goscript/example.com/my/module/index.js'

docs/typescript.md has the full tsconfig.json for typechecking and bundling generated code.

Usage

Compile packages

goscript compile --package ./pkg/... --output ./output

--package takes any Go package pattern and repeats. GoScript compiles the requested packages and every package they import. --skip-dependencies emits only the requested packages and the runtime, for builds that compile dependencies separately. docs/cli.md lists every option.

Run Go tests

goscript test compiles a package's Go tests to TypeScript and runs them with Bun, or in Chromium with --browser. The output follows go test:

goscript test --tags goscript ./...

Compile from TypeScript

import { compile } from 'goscript'

await compile({
  pkg: '.',
  output: './output',
  dir: process.cwd(),
})

Compile from Go

comp, err := compiler.NewCompiler(&compiler.Config{
	Dir:        ".",
	OutputPath: "./output",
}, nil, nil)
if err != nil {
	return err
}
_, err = comp.CompilePackages(ctx, ".")

Compile in the browser

github.com/s4wave/goscript/compiler/wasm builds to WebAssembly and compiles a single Go source file to TypeScript in the page. It accepts files without imports; the website playground uses it.

ts, err := wasm.CompileSource(src, "main")

Features

  • Go language: structs, interfaces, generics, closures, slices, maps, and value copies.
  • Pointers: &x, pointers to pointers, and pointer receivers behave as in Go.
  • Concurrency: goroutines, channels, select, sync, defer, panic, and recover.
  • Exact integers: int64 and uint64 compile to bigint and wrap like Go.
  • Control flow: goto, labels, type switches, and range over iterator functions.
  • Standard library: fmt, strings, sync, time, encoding/json, crypto, and more.
  • Third-party packages: go-git, klauspost/compress, blake3, protobuf-go-lite, and more.
  • Go tests: goscript test runs your Go tests on the output in Bun or Chromium.
  • Large programs: GoScript compiles Spacewave's browser core, including go-git.
  • In the browser: the compiler runs in the page through WebAssembly.

How It Works

Go packages -> type check -> semantic model -> lowered IR -> TypeScript
                                                         + runtime + overrides

GoScript loads packages with the Go toolchain and type-checks them. It then decides which variables need a pointer box, which functions must become async, and how each type maps to TypeScript, before it writes any text. The emitter renders the result, and the compiler copies the @goscript/builtin runtime and any handwritten overrides for packages such as sync, os, and reflect.

A function that can block on a channel, select, or a lock becomes async, and so does every function that calls it. Goroutines run as async tasks on the JavaScript event loop, and no WebAssembly runtime ships with your code.

docs/explainer.md walks through each stage with generated output for structs, pointers, channels, and defer.

Limitations

  • The CLI and APIs take package patterns, not individual .go files.
  • Browser compilation accepts single files without imports. Compile code with imports through the CLI or API.
  • unsafe type-checks, but Sizeof, Alignof, Offsetof, and pointer conversions throw at runtime. Pointer arithmetic and cgo are unsupported.
  • int, uint, and integers narrower than 64 bits are JavaScript numbers. uint and uintptr keep full 64-bit width, but int does not wrap on 64-bit overflow.
  • A standard-library package works when GoScript ships an override for it or it compiles cleanly from Go. Sockets, processes, and plugin loading work only as far as the JavaScript host supports them.
  • reflect covers types, values, struct fields, maps, MakeFunc, FuncOf, and DeepEqual, but not all of the package.
  • goscript test supports a subset of testing and of the go test flags.
  • Async calls and bigint arithmetic cost more than synchronous JavaScript on plain numbers.

Why GoScript

Use GoScript when Go is the source of truth and part of your product runs in a TypeScript runtime: shared validation and business rules, TypeScript packages published from Go code, or Go framework code running in the browser without a rewrite.

GoScript is built against Spacewave, a large Go and TypeScript application framework. Spacewave compiles its browser core plugin through GoScript, including go-git and the go-mysql-server SQL engine, and runs its core package tests through goscript test in CI.

GopherJS shares the goal of running Go in JavaScript and ships its own goroutine scheduler. GoScript emits readable TypeScript modules and maps goroutines onto JavaScript async functions.

Development

bun install
bun run test
bun run lint
bun run build

bun run example compiles and runs example/simple. bun run website:build builds the website and playground. example/app is a full-stack application built on generated TypeScript.

The compliance tests under tests/tests are Go programs compiled, typechecked, and run against expected output.

Contributing

To fix a missing Go behavior, add a focused compiler or compliance test that reproduces it, then implement the behavior in the compiler or runtime stage responsible for it.

Open an issue for Go code GoScript cannot compile, runtime gaps, and missing standard-library overrides.

License

MIT

About

Go to TypeScript transpiler

Topics

Resources

Contributing

Stars

229 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages