https://github.com/aperturerobotics/goscript
Go to TypeScript transpiler
https://github.com/aperturerobotics/goscript
compiler go typescript
Last synced: 6 months ago
JSON representation
Go to TypeScript transpiler
- Host: GitHub
- URL: https://github.com/aperturerobotics/goscript
- Owner: aperturerobotics
- License: mit
- Created: 2017-03-29T00:10:35.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2025-06-27T06:10:24.000Z (about 1 year ago)
- Last Synced: 2025-06-27T09:15:29.185Z (about 1 year ago)
- Topics: compiler, go, typescript
- Language: TypeScript
- Homepage:
- Size: 2.49 MB
- Stars: 14
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# GoScript
[![GoDoc Widget]][GoDoc] [![Go Report Card Widget]][Go Report Card] [](https://deepwiki.com/aperturerobotics/goscript)
[GoDoc]: https://godoc.org/github.com/aperturerobotics/goscript
[GoDoc Widget]: https://godoc.org/github.com/aperturerobotics/goscript?status.svg
[Go Report Card Widget]: https://goreportcard.com/badge/github.com/aperturerobotics/goscript
[Go Report Card]: https://goreportcard.com/report/github.com/aperturerobotics/goscript
## What is GoScript?
GoScript is an experimental **Go to TypeScript compiler** that translates Go code to TypeScript at the AST level. The goal is to enable sharing algorithms and business logic between Go backends and TypeScript frontends.
> Right now goscript looks pretty cool if you problem is "I want this self-sufficient algorithm be available in Go and JS runtimes". gopherjs's ambition, however, has always been "any valid Go program can run in a browser". There is a lot that goes on in gopherjs that is necessary for supporting the standard library, which goes beyond cross-language translation.
>
> — [nevkontakte](https://gophers.slack.com/archives/C039C0R2T/p1745870396945719), developer of [GopherJS](https://github.com/gopherjs/gopherjs)
### 🎯 Why GoScript?
Write once, run everywhere. Share your Go algorithms, business logic, and data structures seamlessly between your backend and frontend without maintaining two codebases.
**Use cases:**
- Sharing business logic between Go services and web apps
- Porting Go algorithms to run in browsers
- Building TypeScript libraries from existing Go code
Go has powerful concurrency support and an excellent standard library. GoScript brings these capabilities to TypeScript with as simple and readable of a translation as possible.
**✅ What works:**
- Structs, interfaces, methods, and functions with full value semantics
- Channels and goroutines (translated to async/await with function coloring)
- Pointers and addressability (via VarRef system)
- Slices, maps, and built-in types
- Control flow (if, for, switch, select, range, defer, etc.)
- Type assertions and interface implementations
- Closures and anonymous functions
- Generics
- Reflection
- Encoding: encoding/json
- Most of the standard library
**🚧 In progress:**
- Reflection edge cases
- Full standard library coverage
- Various other edge cases (see GitHub issues)
**Important Notes**
- Uses JavaScript `number` type (64-bit float, not Go's int types)
- No pointer arithmetic (`uintptr`) or `unsafe` package
- No complex numbers
📖 **Learn more:** [Design document](./design/DESIGN.md) | [Architecture explainer](./docs/explainer.md) | [Compliance tests](./tests/README.md)
🐛 **Found an issue?** Please [open an issue](https://github.com/aperturerobotics/goscript/issues).
## 🚀 Try It
### Prerequisites
GoScript requires [Bun](https://bun.sh) to be installed for running compliance tests:
```bash
# Install Bun
curl -fsSL https://bun.sh/install | bash
```
### Installation
**Option 1: Go Install**
```bash
go install github.com/aperturerobotics/goscript/cmd/goscript@latest
```
**Option 2: NPM** (if available)
```bash
npm install -g goscript
```
### Compilation
```bash
# Try compiling your Go package to TypeScript
goscript compile --package . --output ./dist
```
## 📦 Using Generated Code in Your Project
After compiling your Go code to TypeScript, you'll need to set up your project appropriately.
### TypeScript Configuration
Create or update your `tsconfig.json` with these settings:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "esnext.disposable", "dom"],
"baseUrl": "./",
"paths": {
"@goscript/*": ["./path/to/generated/output/@goscript/*"]
},
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"skipLibCheck": true,
"strict": true
}
}
```
**Important requirements:**
- **`target: "ES2022"` or newer** - Required for `Disposable` and other features
- **`lib: ["esnext.disposable"]`** - Enables TypeScript's disposable types for resource management
- **`baseUrl` and `paths`** - Allows TypeScript to resolve `@goscript/*` imports
- **`moduleResolution: "bundler"`** - Recommended for modern bundlers
You should be able to use any TypeScript bundler to compile the generated TypeScript.
## 🛠️ Integration & Usage
### Command Line
```bash
goscript compile --package ./my-go-code --output ./dist
```
**Options:**
- `--package ` - Go package to compile (default: ".")
- `--output ` - Output directory for TypeScript files
### Programmatic API
**Go:**
```go
import "github.com/aperturerobotics/goscript/compiler"
conf := &compiler.Config{OutputPath: "./dist"}
comp, err := compiler.NewCompiler(conf, logger, nil)
_, err = comp.CompilePackages(ctx, "your/package/path")
```
**Node.js:**
```typescript
import { compile } from 'goscript'
await compile({
pkg: './my-go-package',
output: './dist',
})
```
### Frontend Frameworks
**React + GoScript:**
```typescript
import { NewCalculator } from '@goscript/myapp/calculator'
function CalculatorApp() {
const [calc] = useState(() => NewCalculator())
const handleAdd = () => {
const result = calc.Add(5, 3)
setResult(result)
}
return Add 5 + 3
}
```
**Vue + GoScript:**
```vue
import { NewUser, FindUserByEmail } from '@goscript/myapp/user'
const users = ref([NewUser(1, 'Alice', 'alice@example.com')])
const searchUser = (email: string) => {
return FindUserByEmail(users.value, email)
}
```
## 💡 See It In Action
See the [example/app](./example/app) for a full todo list application using GoScript with tRPC, Drizzle ORM, and React, or [example/simple](./example/simple) for a comprehensive demo of language features.
### Example: User Management
**Go Code** (`user.go`):
```go
package main
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
func (u *User) IsValid() bool {
return u.Name != "" && u.Email != ""
}
func NewUser(id int, name, email string) *User {
return &User{ID: id, Name: name, Email: email}
}
func FindUserByEmail(users []*User, email string) *User {
for _, user := range users {
if user.Email == email {
return user
}
}
return nil
}
```
**Compile it:**
```bash
goscript compile --package . --output ./dist
```
**Generated TypeScript** (`user.gs.ts`):
```typescript
export class User {
public ID: number = 0
public Name: string = ''
public Email: string = ''
public IsValid(): boolean {
const u = this
return u.Name !== '' && u.Email !== ''
}
constructor(init?: Partial) {
if (init) Object.assign(this, init)
}
}
export function NewUser(id: number, name: string, email: string): User {
return new User({ ID: id, Name: name, Email: email })
}
export function FindUserByEmail(users: User[], email: string): User | null {
for (let user of users) {
if (user.Email === email) {
return user
}
}
return null
}
```
**Use in your frontend:**
```typescript
import { NewUser, FindUserByEmail } from '@goscript/myapp/user'
// Same logic, now in TypeScript!
const users = [
NewUser(1, 'Alice', 'alice@example.com'),
NewUser(2, 'Bob', 'bob@example.com'),
]
const alice = FindUserByEmail(users, 'alice@example.com')
console.log(alice?.IsValid()) // true
```
### Example: Async Processing with Channels
**Go Code:**
```go
func ProcessMessages(messages []string) chan string {
results := make(chan string, len(messages))
for _, msg := range messages {
go func(m string) {
// Simulate processing
processed := "✓ " + m
results <- processed
}(msg)
}
return results
}
```
**Generated TypeScript:**
```typescript
export function ProcessMessages(messages: string[]): $.Channel {
let results = $.makeChannel(messages.length, '')
for (let msg of messages) {
queueMicrotask(async (m: string) => {
let processed = '✓ ' + m
await results.send(processed)
})(msg)
}
return results
}
```
**Use with async/await:**
```typescript
import { ProcessMessages } from '@goscript/myapp/processor'
async function handleMessages() {
const channel = ProcessMessages(['hello', 'world', 'goscript'])
// Receive processed messages
for (let i = 0; i < 3; i++) {
const result = await channel.receive()
console.log(result) // "✓ hello", "✓ world", "✓ goscript"
}
}
```
## 🤝 How You Can Help
- Try GoScript on your code and [report issues](https://github.com/aperturerobotics/goscript/issues)
- Check the [compliance tests](./tests/README.md) for current progress
- Contribute test cases for edge cases you discover
## License
MIT