将 Go 代码转译为可读的 TypeScript
Goscript: Transpile Go to human-readable TypeScript

原始链接: https://github.com/aperturerobotics/goscript

## GoScript:Go 与 TypeScript 之间的逻辑共享 GoScript 是一个实验性的 Go 到 TypeScript 编译器,在 AST 级别将 Go 代码翻译成 TypeScript。其主要目标是促进代码共享——特别是算法和业务逻辑——在 Go 后端和 TypeScript 前端之间,避免代码重复。与旨在在浏览器中运行*任何* Go 程序的 GopherJS 不同,GoScript 专注于跨语言翻译。 目前,GoScript 成功翻译了结构体、接口、方法、函数、通道(转换为 async/await)、指针、切片、映射、控制流和闭包。它需要 Bun 来进行合规性测试,并利用 ES2022+ 特性,配置侧重于打包器。 **主要用例:** 共享业务逻辑、将 Go 算法移植到浏览器以及从现有的 Go 代码构建 TypeScript 库。 **限制:** 它使用 JavaScript 数字(64 位浮点数),缺乏指针运算/`unsafe` 包,并且不支持复数。 示例和完整的待办事项应用程序演示可供使用,展示了与 React、Vue、tRPC 和 Drizzle ORM 的集成。你可以在项目的 GitHub 仓库中找到更多信息,包括设计文档和合规性测试。

## Goscript:Go 到 TypeScript 转换器 一个名为 **Goscript** 的新项目旨在将 Go 代码转换为人类可读的 TypeScript。 这在 Hacker News 上引发了关于从 Go 转换的可行性讨论,考虑到将 Go 结构转换为 TypeScript 接口的工具(如 Quicktype、Huma、Tygo 和 Guts)的普及。 评论者争论是否用其他语言编写并转换为 Go 可能会更有吸引力,但指出在平台必要性之外,这种方法在历史上缺乏成功(例如浏览器中的 JavaScript)。 进一步的讨论涉及 LLVM IR 反向器作为通用解决方案的潜力,但人们担心编译过程中信息丢失会使准确的反向变得困难,即使对于 LLM 也是如此。 也有人建议将其转换为静态 Python 并利用 py2many。 最后,一条有趣的评论质疑 Go 本身是否已经人类可读的前提,明确目标是 *目标* 代码的可读性。
相关文章

原文

GoDoc Widget Go Report Card Widget Ask DeepWiki

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, developer of GopherJS

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

🚧 In progress:

  • Reflection support
  • Standard library coverage
  • Generics

Known limitations:

  • 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 | Architecture explainer | Compliance tests

🐛 Found an issue? Please open an issue.

GoScript requires Bun to be installed for running compliance tests:

# Install Bun
curl -fsSL https://bun.sh/install | bash

Option 1: Go Install

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

Option 2: NPM (if available)

# 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.

Create or update your tsconfig.json with these settings:

{
  "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

goscript compile --package ./my-go-code --output ./dist

Options:

  • --package <path> - Go package to compile (default: ".")
  • --output <dir> - Output directory for TypeScript files

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:

import { compile } from 'goscript'

await compile({
  pkg: './my-go-package',
  output: './dist',
})

React + GoScript:

import { NewCalculator } from '@goscript/myapp/calculator'

function CalculatorApp() {
  const [calc] = useState(() => NewCalculator())

  const handleAdd = () => {
    const result = calc.Add(5, 3)
    setResult(result)
  }

  return <button onClick={handleAdd}>Add 5 + 3</button>
}

Vue + GoScript:

<script setup lang="ts">
import { NewUser, FindUserByEmail } from '@goscript/myapp/user'

const users = ref([NewUser(1, 'Alice', '[email protected]')])

const searchUser = (email: string) => {
  return FindUserByEmail(users.value, email)
}
</script>

See the example/app for a full todo list application using GoScript with tRPC, Drizzle ORM, and React, or example/simple for a comprehensive demo of language features.

Go Code (user.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:

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

Generated TypeScript (user.gs.ts):

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<User>) {
    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:

import { NewUser, FindUserByEmail } from '@goscript/myapp/user'

// Same logic, now in TypeScript!
const users = [
  NewUser(1, 'Alice', '[email protected]'),
  NewUser(2, 'Bob', '[email protected]'),
]

const alice = FindUserByEmail(users, '[email protected]')
console.log(alice?.IsValid()) // true

Example: Async Processing with Channels

Go Code:

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:

export function ProcessMessages(messages: string[]): $.Channel<string> {
  let results = $.makeChannel<string>(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:

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"
  }
}

MIT

联系我们 contact @ memedata.com