TypeScript-Go Limitations: Critical Gaps in the Native Corsa Compiler

TypeScript-Go (codenamed Corsa) lacks a public Go API, enforces read-only virtual file systems that panic on write operations, runs watch mode as a non-incremental prototype, and ships with incomplete Language Service, JSDoc, and JavaScript declaration emit features.

Microsoft's typescript-go repository represents a ground-up rewrite of the TypeScript compiler in Go, aiming for dramatic performance improvements in parsing and type checking. While the core compilation pipeline successfully handles standard TypeScript projects, several production-critical features remain marked as prototype or not ready. Understanding these typescript-go limitations is essential before adopting the tool for production builds or replacing the legacy TypeScript compiler.

Missing Public API and Embedding Support

The most significant architectural limitation is the absence of a public Go API. According to the repository's README.md (lines 42-44), the internal/compiler package is not exported, meaning libraries cannot import the compiler as a dependency. The only supported entry point is the command-line interface in cmd/tsgo/main.go.

Attempting to embed the compiler into a Go application fails because the core logic resides in unexported internal packages:

// This embedding pattern is currently impossible:
package main

import (
    "github.com/microsoft/typescript-go/internal/compiler" // ❌ Not exported
)

func main() {
    // Compile on-the-fly...
}

This restriction forces all integrations to shell out to the tsgo binary rather than using the compiler as a library.

Virtual File System Constraints

The virtual file system (VFS) wrapper in internal/vfs/iovfs/iofs.go intentionally aborts on any write operation, making the current implementation strictly read-only.

Write Operations Trigger Panics

As implemented in iofs.go (lines 90-104), the following methods panic with "not supported" errors: WriteFile, AppendFile, MkdirAll, Remove, and Chtimes. This design prevents the compiler from emitting files to custom file systems:

package main

import (
    "io/fs"
    "os"
    "github.com/microsoft/typescript-go/internal/vfs/iovfs"
)

type readOnlyFS struct{ fs.FS }

func main() {
    ro := readOnlyFS{FS: os.DirFS(".")}
    v := iovfs.From(ro, true) // useCaseSensitiveFileNames = true
    
    // This line triggers a runtime panic:
    _ = v.WriteFile("/tmp/out.js", []byte("console.log('hi')"), 0644)
}

Result: panic: writeFile not supported.

Case Sensitivity Handling

The VFS assumes case-sensitive path handling (lines 41-43 in iofs.go). Projects relying on Windows-style case-insensitivity must provide a custom fs.FS implementation that normalizes case, as the default wrapper does not handle case collisions automatically.

Watch Mode and Incremental Build Limitations

Watch mode exists only as a prototype that lacks incremental re-checking. As noted in README.md (lines 38-40), editing any file triggers a full project recompilation from scratch. This behavior makes watch mode unsuitable for large codebases during development:


# Starts the prototype watcher

npx tsgo -w .

# Any file edit causes complete re-type-checking

While incremental build tracking exists for the command-line tsgo build mode, the watch implementation does not reuse prior type-checking results, eliminating the performance benefits typically associated with watch mode.

JavaScript and JSDoc Compatibility Gaps

The Go port deliberately removed several legacy JavaScript and JSDoc features that were supported in the original TypeScript compiler.

Removed JSDoc Tag Types

According to CHANGES.md (lines 106-112), the compiler no longer creates dedicated AST node types for @class, @throws, @author, and @enum. These tags parse only as generic JSDocTag nodes, breaking language service features like hover information that relied on the specific node types:

/** @class */
function Legacy() { this.x = 0; }

Running tsgo on this file produces no class-type information in generated .d.ts files, and the Language Service cannot surface specific documentation for the Legacy constructor.

Unsupported Closure Compiler Syntax

The parser no longer recognizes Closure-specific type syntax documented in CHANGES.md (lines 99-105). The following constructs produce syntax errors:

  • Postfix nullable/non-nullable types: T? or T!
  • Closure function type syntax: function(string,string): void
  • Module namepaths

Projects using these annotations must migrate to standard TypeScript syntax before compiling with tsgo.

Incomplete Declaration Emit for JavaScript

Declaration file generation (.d.ts emit) works for TypeScript sources but remains in progress for JavaScript files (README.md, lines 36-38). Compiling .js files with declaration emit enabled produces missing or inaccurate type definitions.

Language Service Protocol (LSP) Status

The Language Service implementation is in progress (README.md, lines 41-43). While core features function, edge-case behaviors—including certain refactorings and quick-fixes—may be missing or unstable. Developers using tsgo for IDE support should expect occasional service interruptions or incorrect code actions compared to the production TypeScript Language Server.

Parser and Transformer Edge Cases

The codebase contains numerous TODO comments indicating unfinished paths. The parser in internal/parser/parser.go and transformers in internal/transformers/ contain unhandled cases for decorator handling and error recovery. Additionally, internal/tsoptions/tsconfigparsing.go contains TODOs for suggestion support, indicating incomplete command-line option validation.

Practical Examples of Current Limitations

Successful Basic Compilation

Standard TypeScript compilation works as expected:

cat > hello.ts <<'EOF'
function greet(name: string) {
    console.log("Hello, " + name);
}
greet("World");
EOF

npx tsgo hello.ts  # Generates hello.js

Attempting to Use the Go API

As confirmed by the project structure, importing the compiler fails:

// Attempting to import internal packages results in a build error
import "github.com/microsoft/typescript-go/internal/compiler" 
// Go error: use of internal package ... not allowed

Virtual File System Write Failure

Custom build tools cannot use the provided VFS for output:

// Results in panic: writeFile not supported
vfs.WriteFile("/output/app.js", source, 0644)

Watch Mode Full Rebuild

Monitoring a large project demonstrates the prototype limitation:

npx tsgo -w ./src

# Edit src/index.ts

# Observed: Full type-check re-runs (no incremental optimization)

Summary

  • No Public API: The compiler exists only as a CLI tool; Go libraries cannot import internal/compiler.
  • Read-Only VFS: Write operations panic in internal/vfs/iovfs/iofs.go; case-insensitive paths require custom implementations.
  • Prototype Watch Mode: No incremental re-checking; every change triggers full recompilation.
  • JSDoc Regressions: @class, @throws, @author, and @enum tags lose specialized handling; Closure syntax is unsupported.
  • Incomplete JS Support: Declaration emit for JavaScript files and full Language Service features remain works-in-progress.
  • Parser TODOs: Edge cases in decorators and error recovery remain unimplemented.

Frequently Asked Questions

Can I import TypeScript-Go as a library in my Go application?

No. The compiler API resides in internal/ packages that are not exported. According to cmd/tsgo/main.go and the repository structure, only the tsgo CLI binary is supported. You must shell out to the binary or fork and modify the internal package visibility.

Does TypeScript-Go support incremental compilation in watch mode?

No. While tsgo build supports incremental builds, the watch mode (-w flag) is a prototype that recompiles the entire project from scratch on every file change. The README.md (lines 38-40) explicitly notes this limitation, making watch mode unsuitable for large projects.

What JSDoc tags are unsupported in TypeScript-Go?

The compiler no longer recognizes @class, @throws, @author, and @enum as distinct AST node types, as documented in CHANGES.md (lines 106-112). These tags parse as generic JSDocTag nodes, breaking IDE features that depend on specific tag semantics.

Is the Language Server Protocol (LSP) fully implemented?

No. The Language Service is listed as in progress in README.md (lines 41-43). While basic functionality works, advanced features like specific refactorings and quick-fixes may be missing or unstable compared to the production TypeScript compiler's language service.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →