How to Integrate typescript-go into an Existing Go Project: 3 Methods Explained
You can integrate typescript-go into an existing Go project by either running the tsgo CLI tool, embedding the compiler as a library via execute.CommandLine with a custom System implementation, or deploying the JSON-RPC/MessagePack API server for cross-process communication.
typescript-go is Microsoft's official TypeScript compiler rewritten in Go, offering full compatibility with existing tsconfig.json configurations while providing native Go APIs for programmatic control. Whether you need a drop-in replacement for tsc or a compiler embedded within your build pipeline, the repository provides three distinct integration paths based on the cmd/tsgo, internal/execute, and internal/api packages.
Installation and Module Configuration
Add the typescript-go module to your project using the standard Go toolchain:
go get github.com/microsoft/typescript-go@latest
This updates your go.mod to include the dependency:
module your/project
go 1.26
require github.com/microsoft/typescript-go v0.0.0-<commit-hash>
The module exposes both high-level CLI wrappers and low-level compiler primitives, allowing you to choose the appropriate abstraction level for your integration.
Method 1: Running the tsgo CLI Tool
The simplest integration method uses the cmd/tsgo binary as a drop-in replacement for the traditional TypeScript compiler. This approach requires minimal code changes and supports all standard tsc flags.
Build the CLI from source:
go build -o tsgo ./cmd/tsgo
./tsgo --project tsconfig.json
Under the hood, cmd/tsgo/main.go parses command-line arguments and delegates to execute.CommandLine in internal/execute/tsc/compile.go. This function orchestrates the entire compilation pipeline including configuration parsing, type checking, and file emission.
When to use this method: Choose the CLI approach when you need a standalone binary for build scripts or CI/CD pipelines without requiring programmatic access to compilation results.
Method 2: Embedding the Compiler as a Library
For custom build pipelines or IDE integrations, embed the compiler directly by implementing the tsc.System interface and invoking execute.CommandLine programmatically.
The interface definition resides in internal/execute/tsc/compile.go and requires methods for file system access, environment variables, and output writing. Reference the osSys type in cmd/tsgo/sys.go as a production-ready implementation template.
Create a minimal wrapper:
package tsintegration
import (
"io"
"os"
"time"
"github.com/microsoft/typescript-go/internal/bundled"
"github.com/microsoft/typescript-go/internal/execute/tsc"
"github.com/microsoft/typescript-go/internal/tspath"
"github.com/microsoft/typescript-go/internal/vfs"
"github.com/microsoft/typescript-go/internal/vfs/osvfs"
"golang.org/x/term"
)
type System struct {
writer io.Writer
fs vfs.FS
defaultLibraryPath string
cwd string
start time.Time
}
func (s *System) Writer() io.Writer { return s.writer }
func (s *System) FS() vfs.FS { return s.fs }
func (s *System) DefaultLibraryPath() string { return s.defaultLibraryPath }
func (s *System) GetCurrentDirectory() string { return s.cwd }
func (s *System) WriteOutputIsTTY() bool { return term.IsTerminal(int(os.Stdout.Fd())) }
func (s *System) GetWidthOfTerminal() int { return 80 }
func (s *System) GetEnvironmentVariable(n string) string { return os.Getenv(n) }
func (s *System) Now() time.Time { return time.Now() }
func (s *System) SinceStart() time.Duration { return time.Since(s.start) }
func NewSystem() *System {
cwd, _ := os.Getwd()
return &System{
writer: os.Stdout,
cwd: tspath.NormalizePath(cwd),
fs: bundled.WrapFS(osvfs.FS()),
defaultLibraryPath: bundled.LibPath(),
start: time.Now(),
}
}
// Compile executes the TypeScript compiler with the provided arguments.
func Compile(args []string) tsc.ExitStatus {
sys := NewSystem()
result := execute.CommandLine(sys, args, nil)
return result.Status
}
Use the wrapper in your application:
package main
import (
"fmt"
"yourproject/tsintegration"
)
func main() {
// Equivalent to: tsgo --project tsconfig.json --noEmit
status := tsintegration.Compile([]string{"--project", "tsconfig.json", "--noEmit"})
if status == 0 {
fmt.Println("TypeScript compilation succeeded")
} else {
fmt.Printf("Compilation failed with exit code %d\n", status)
}
}
The execute.CommandLine function handles the complete compilation lifecycle: parsing tsconfig.json, creating a compiler.Program, running type checking, and managing incremental builds or watch modes.
When to use this method: Choose library embedding when you need to capture compilation status codes, intercept diagnostics, or integrate TypeScript compilation into larger Go-based build systems.
Method 3: Deploying the JSON-RPC/MessagePack API Server
For language-server integrations or scenarios requiring process isolation, typescript-go provides a stdio-based API server via internal/api.
Initialize the server:
package main
import (
"context"
"os"
"os/signal"
"syscall"
"github.com/microsoft/typescript-go/internal/api"
"github.com/microsoft/typescript-go/internal/bundled"
)
func main() {
opts := &api.StdioServerOptions{
Err: os.Stderr,
Cwd: ".",
DefaultLibraryPath: bundled.LibPath(),
Async: false, // false = JSON-RPC, true = MessagePack
}
srv := api.NewStdioServer(opts)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
if err := srv.Run(ctx); err != nil {
panic(err)
}
}
The server reads requests from stdin (or named pipes) and returns compilation results via the configured protocol. The cmd/tsgo/api.go file provides the reference implementation for launching this server from command-line contexts.
When to use this method: Choose the API server for VS Code extensions, long-running build daemons, or polyglot environments where Go code must communicate with TypeScript tooling written in other languages.
Integration Method Comparison
Select the appropriate integration strategy based on your architectural requirements:
- CLI Tool: Use when replacing
tscin existing build scripts without code changes. Entry point:cmd/tsgo/main.go. - Library Embedding: Use for custom build orchestration in Go. Entry point:
execute.CommandLinewith a customSystemimplementation. - API Server: Use for IDE integrations or cross-language services. Entry point:
api.NewStdioServer.
Summary
Integrating typescript-go into an existing Go project offers three distinct approaches depending on your isolation and control requirements:
- Install via
go get github.com/microsoft/typescript-goto add the module to your project - Run the CLI by building
cmd/tsgofor drop-intscreplacement functionality - Embed as a library by implementing the
tsc.Systeminterface and callingexecute.CommandLinefrominternal/execute/tsc/compile.go - Deploy the API server using
api.NewStdioServerfrominternal/apifor JSON-RPC or MessagePack-based inter-process communication - Reference
cmd/tsgo/sys.gofor the canonicalSystemimplementation when embedding the compiler
Frequently Asked Questions
Can typescript-go use existing tsconfig.json files?
Yes. The execute.CommandLine function in internal/execute/tsc/compile.go fully parses and respects tsconfig.json configurations, including compiler options, file includes, and project references. Pass --project tsconfig.json in your arguments array to specify the configuration file path.
How does typescript-go handle the TypeScript standard library?
The compiler bundles standard library definitions (.d.ts files) internally via the internal/bundled package. When implementing the tsc.System interface, return bundled.LibPath() from the DefaultLibraryPath() method to provide access to these embedded type definitions without requiring external node_modules installations.
What is the performance difference between library embedding and the CLI?
Both methods use the same underlying compilation engine in internal/execute/tsc/compile.go. Library embedding eliminates process startup overhead and allows reusing vfs.FS instances across multiple compilations, potentially improving performance for incremental builds or watch mode implementations compared to spawning separate CLI processes.
Is the API server compatible with the Language Server Protocol (LSP)?
No. The internal/api server uses a custom JSON-RPC/MessagePack protocol specific to typescript-go's compiler operations, distinct from LSP. It exposes compilation and project management functions rather than editor-oriented features like hover information or go-to-definition. For LSP functionality, you would need to build a separate adapter layer that calls the typescript-go library programmatically.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →