# How to Handle TypeScript Enums with typescript-go: Complete Compiler Pipeline Guide

> Learn how typescript-go handles Go enums with its five-stage compiler pipeline. Understand parsing, AST generation, runtime transformation, and more for seamless integration.

- Repository: [Microsoft/typescript-go](https://github.com/microsoft/typescript-go)
- Tags: tutorial
- Published: 2026-04-25

---

**The `microsoft/typescript-go` compiler transforms TypeScript enum declarations into runtime-compatible output through a five-stage pipeline involving parsing, AST generation, runtime transformation, encoding, and printing.**

The `microsoft/typescript-go` project is a ground-up Go port of the TypeScript compiler that parses TypeScript source into an internal AST before code generation. When handling TypeScript enums, the compiler implements the same JavaScript runtime semantics as the original TypeScript compiler but uses Go-based internal structures and transformations.

## Understanding the Enum Transformation Pipeline

TypeScript enums undergo a complete transformation pipeline from raw syntax to executable output. Each stage utilizes specific files and functions within the `typescript-go` repository.

### Parsing TypeScript Enum Declarations

The process begins in [`internal/parser/parser.go`](https://github.com/microsoft/typescript-go/blob/main/internal/parser/parser.go), where the `Parser.parseEnumDeclaration` method consumes the `enum` keyword and constructs an AST node.

```go
// internal/parser/parser.go (lines 2131-2147)
func (p *Parser) parseEnumDeclaration(pos int, jsdoc jsdocScannerInfo, modifiers *ast.ModifierList) *ast.Node {
    p.parseExpected(ast.KindEnumKeyword)
    name := p.parseIdentifier()
    // parse members inside `{ … }`
    members := p.parseDelimitedList(PCEnumMembers, (*Parser).parseEnumMember)
    return p.finishNode(p.factory.NewEnumDeclaration(modifiers, name, members), pos)
}

```

This function returns an `*ast.EnumDeclaration` containing the modifiers, identifier name, and an `*EnumMemberList` representing the individual enum members.

### Generated AST Structure

The concrete Go struct for enum declarations is automatically generated by [`_scripts/generate-go-ast.ts`](https://github.com/microsoft/typescript-go/blob/main/_scripts/generate-go-ast.ts) and defined in [`internal/ast/ast_generated.go`](https://github.com/microsoft/typescript-go/blob/main/internal/ast/ast_generated.go) (lines 2541-2550).

```go
// internal/ast/ast_generated.go (excerpt)
type EnumDeclaration struct {
    DeclarationBase
    StatementBase
    ExportableBase
    ModifiersBase
    CompositeBase
    name    *IdentifierNode
    Members *EnumMemberList
}

```

You should never manually edit this struct. The generator creates Go types that mirror the TypeScript compiler's internal AST structure, ensuring type safety and consistency across the codebase.

### Runtime Syntax Transformation

The critical transformation logic resides in [`internal/transformers/tstransforms/runtimesyntax.go`](https://github.com/microsoft/typescript-go/blob/main/internal/transformers/tstransforms/runtimesyntax.go) (lines 190-210). The `RuntimeSyntaxTransformer` emits the classic Immediately Invoked Function Expression (IIFE) pattern used by TypeScript to create the runtime enum object.

The `transformEnumDeclaration` method constructs the variable declaration and IIFE:

```go
// internal/transformers/tstransforms/runtimesyntax.go (excerpt)
func (tx *RuntimeSyntaxTransformer) transformEnumDeclaration(node *ast.EnumDeclaration) *ast.Node {
    // 1. Emit a `var <EnumName>;` declaration
    // 2. Emit an IIFE that populates members
    // 3. Return the combined statement list
}

```

The helper `getEnumQualifiedElement` (in the same file) builds qualified property references for reverse mappings:

```go
func (tx *RuntimeSyntaxTransformer) getEnumQualifiedElement(enum *ast.EnumDeclaration, member *ast.EnumMember) *ast.Expression {
    prop := tx.getNamespaceQualifiedElement(
        tx.getNamespaceContainerName(enum.AsNode()),
        tx.getExpressionForPropertyName(member),
    )
    tx.EmitContext().AddEmitFlags(prop, printer.EFNoComments|printer.EFNoNestedComments|
        printer.EFNoSourceMap|printer.EFNoNestedSourceMaps)
    return prop
}

```

This produces the characteristic reverse mapping pattern where `Color["Red"] = 0` and `Color[0] = "Red"` are both established.

### Language Service Encoding

For incremental compilation and language service features, enum nodes are serialized in [`internal/api/encoder/encoder_generated.go`](https://github.com/microsoft/typescript-go/blob/main/internal/api/encoder/encoder_generated.go) (lines 143-144). This ensures that enum metadata persists across compilation sessions for features like IntelliSense and go-to-definition.

### Final Code Generation

The `Printer` phase in [`internal/printer/printer.go`](https://github.com/microsoft/typescript-go/blob/main/internal/printer/printer.go) (lines 3734-3744) handles the actual output generation using `emitEnumDeclaration`:

```go
// internal/printer/printer.go (excerpt)
func (p *Printer) emitEnumDeclaration(node *ast.EnumDeclaration) {
    state := p.enterNode(node.AsNode())
    p.emitModifierList(node.AsNode(), node.Modifiers(), false)
    p.writeKeyword("enum")
    p.writeSpace()
    p.emitBindingIdentifier(node.Name().AsIdentifier())
    p.writeSpace()
    p.writePunctuation("{")
    p.emitList((*Printer).emitEnumMemberNode, node.AsNode(), node.Members, LFEnumMembers)
    p.writePunctuation("}")
    p.exitNode(node.AsNode(), state)
}

```

The printer outputs the original `enum` syntax for declaration files, while the transformed IIFE statements (produced by the `RuntimeSyntaxTransformer`) are printed by the standard statement emitter for the runtime output.

## Querying Enum Values in Generated Code

When working with the compiled output programmatically, you can introspect enum values by traversing the AST using utility functions. This is useful for custom code generators or analysis tools built on top of `typescript-go`:

```go
// Example: find the numeric value of a generated enum member
func EnumMemberValue(enumName, member string, src *ast.SourceFile) (int, bool) {
    var val int
    found := false
    ast.ForEachChild(src, func(n *ast.Node) bool {
        if ast.IsEnumDeclaration(n) && n.Name().Text() == enumName {
            for i := 0; i < n.Members.Length(); i++ {
                m := n.Members.Get(i)
                if m.Name().Text() == member {
                    if lit := m.Initializer(); lit != nil && ast.IsNumericLiteral(lit) {
                        fmt.Sscanf(lit.Text(), "%d", &val)
                        found = true
                        return false
                    }
                }
            }
        }
        return true
    })
    return val, found
}

```

This pattern allows Go-based tooling to extract specific enum metadata from the compiled TypeScript source without parsing the text manually.

## Compiler Option Enum Maps

Beyond source-code enums, `typescript-go` uses enum maps for command-line options (such as `--watchFile`) in [`internal/tsoptions/enummaps.go`](https://github.com/microsoft/typescript-go/blob/main/internal/tsoptions/enummaps.go). These utilize the `OrderedMap` pattern to map string values to their corresponding enum types:

```go
// internal/tsoptions/enummaps.go (excerpt)
var watchFileEnumMap = collections.NewOrderedMapFromList([]collections.MapEntry[string, any]{
    {Key: "watchFile", Value: "WatchFileKind"},
    // …
})

```

When extending the compiler with new command-line options that require enum values, you add entries to the appropriate map in this file, and the parser automatically handles string-to-value conversion.

## Summary

- **Parsing**: The `Parser.parseEnumDeclaration` function in [`internal/parser/parser.go`](https://github.com/microsoft/typescript-go/blob/main/internal/parser/parser.go) creates `EnumDeclaration` nodes from TypeScript source.
- **AST Generation**: Go structs for enums are auto-generated in [`internal/ast/ast_generated.go`](https://github.com/microsoft/typescript-go/blob/main/internal/ast/ast_generated.go) via [`_scripts/generate-go-ast.ts`](https://github.com/microsoft/typescript-go/blob/main/_scripts/generate-go-ast.ts).
- **Transformation**: `RuntimeSyntaxTransformer` in [`runtimesyntax.go`](https://github.com/microsoft/typescript-go/blob/main/runtimesyntax.go) emits the IIFE pattern that implements JavaScript enum semantics.
- **Encoding**: [`encoder_generated.go`](https://github.com/microsoft/typescript-go/blob/main/encoder_generated.go) serializes enum nodes for language service persistence.
- **Printing**: `Printer.emitEnumDeclaration` in [`printer.go`](https://github.com/microsoft/typescript-go/blob/main/printer.go) outputs the final syntax.
- **Introspection**: Use `ast.ForEachChild` with type guards like `ast.IsEnumDeclaration` to query enum values programmatically.

## Frequently Asked Questions

### How does typescript-go preserve TypeScript enum runtime behavior?

The `RuntimeSyntaxTransformer` implements the same IIFE pattern used by the original TypeScript compiler. By emitting `var` declarations followed by immediately invoked function expressions that assign both forward and reverse mappings (e.g., `Color["Red"] = 0` and `Color[0] = "Red"`), the generated output maintains JavaScript-compatible enum semantics, including support for computed values and reverse lookups.

### Where is the enum AST structure defined in the source code?

The `EnumDeclaration` struct is defined in [`internal/ast/ast_generated.go`](https://github.com/microsoft/typescript-go/blob/main/internal/ast/ast_generated.go) (lines 2541-2550). This file is machine-generated by [`_scripts/generate-go-ast.ts`](https://github.com/microsoft/typescript-go/blob/main/_scripts/generate-go-ast.ts) and should not be manually modified. The struct embeds several base types (`DeclarationBase`, `StatementBase`, `ExportableBase`) to provide common AST node functionality.

### Can I extract specific enum values from the AST using Go code?

Yes. Use the `ast.ForEachChild` function to traverse the `*ast.SourceFile`, checking for `ast.IsEnumDeclaration` nodes. Iterate through the `Members` field (type `*EnumMemberList`) and inspect `Initializer()` nodes for numeric literals or string literals to extract the compiled values.

### How are compiler option enums different from source code enums?

Compiler option enums in [`internal/tsoptions/enummaps.go`](https://github.com/microsoft/typescript-go/blob/main/internal/tsoptions/enummaps.go) are mapping structures used for parsing command-line arguments, while source code enums represent TypeScript constructs being compiled. The former use `OrderedMap` instances to map CLI string flags to internal constants, whereas the latter follow the full parsing-to-printing pipeline described in this guide.