# How typescript-go Implements Go Type to TypeScript Type Mapping

> Discover how typescript-go maps Go types to TypeScript types using native Go structs and bit-flag constants for a precise one-to-one representation in the internal checker package.

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

---

**typescript-go implements the TypeScript type system by representing every TypeScript type as native Go structs and bit-flag constants, creating a static one-to-one mapping defined in the `internal/checker` package.**

The `microsoft/typescript-go` repository contains a complete Go port of the TypeScript compiler. Rather than converting between Go and TypeScript types at runtime, the codebase defines a comprehensive **Go type to TypeScript type mapping** where TypeScript constructs are modeled directly as Go values. This architecture allows the compiler to perform type checking using native Go data structures that mirror the original TypeScript type system exactly.

## Architecture of the Type System Mapping

The mapping operates as a static implementation layer. TypeScript types are not translated from Go types; instead, the Go codebase *is* the TypeScript type system. Every type construct—from primitives to complex generics—has a corresponding Go struct or flag constant in `internal/checker`.

### Primitive Types as Bit-Mask Flags

Primitive TypeScript types utilize a **bit-mask flag system** defined in [`internal/core/constants.go`](https://github.com/microsoft/typescript-go/blob/main/internal/core/constants.go). The `TypeFlags` constants represent intrinsic types like `any`, `unknown`, `string`, `number`, `boolean`, `void`, and `never`.

The `checker.Type` struct stores these flags in its `flags` field. Intrinsic types are created via the `newIntrinsicType` method:

```go
// internal/checker/checker.go (line 964)
c.anyType = c.newIntrinsicType(core.TypeFlagsAny, "any")

```

This approach allows the type checker to perform fast bitwise operations to determine type categories. For example, checking if a type is the `any` type involves a simple bitwise AND operation against `TypeFlagsAny`.

### Complex Object Types via ObjectFlags

For structured types—including classes, interfaces, arrays, tuples, and mapped types—`typescript-go` employs **ObjectFlags**. These bit masks are stored in the `objectFlags` field of `checker.Type` and defined alongside `TypeFlags` in the core constants.

When constructing object types, creation functions like `newObjectType` set appropriate flags to identify the type category:

- `ObjectFlagsClass` for class types
- `ObjectFlagsInterface` for interface types  
- `ObjectFlagsArray` for array types
- `ObjectFlagsMapped` for mapped types

The `checker.Type` struct also contains a `mapper *TypeMapper` field to handle generic instantiations, linking concrete type arguments to their parameters.

## Specialized Type Representations

Beyond bit flags, distinct Go structs model specific TypeScript type categories that require additional metadata.

### Literal Types as Dedicated Structs

String, numeric, and boolean literals receive specialized struct definitions that embed the base `checker.Type`:

- `StringLiteralType` sets `TypeFlagsStringLiteral` and stores the literal string value
- `NumberLiteralType` sets `TypeFlagsNumberLiteral` for numeric constants  
- `BooleanLiteralType` handles `true` and `false` literals with `TypeFlagsBooleanLiteral`

Helper functions like `newStringLiteralType` construct these instances, allowing the checker to treat literal values as subtypes of their corresponding primitive types while preserving the exact value for literal type checking.

### String Mapping Types

Template literal type manipulations like `Uppercase<T>` and `Lowercase<T>` map to the `StringMappingType` struct (defined in [`internal/checker/types.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/types.go) around line 401). These types carry `TypeFlagsStringMapping` and maintain references to their target type and transformation mapper:

```go
// Checking for string mapping types
if t.flags&core.TypeFlagsStringMapping != 0 {
    target := t.AsStringMappingType().Target()
    // Process the underlying target type...
}

```

## Generic Type Substitution with TypeMapper

Generic type parameters and type mappings utilize a hierarchy of mapper structs defined in [`internal/checker/mapper.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/mapper.go). When instantiating a generic type, the checker builds a mapper that substitutes type parameters with concrete arguments:

- `SimpleTypeMapper` maps single parameters to arguments
- `ArrayTypeMapper` handles multiple type parameters  
- `MergedTypeMapper` combines multiple mapping operations

The resulting mapper is stored in the type's `mapper` field, enabling lazy resolution of generic types during type checking.

## Composite Type Construction

Union and intersection types aggregate multiple types into single constructs. These map to `UnionType` and `IntersectionType` structs in [`internal/checker/types.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/types.go), which hold slices of constituent `*Type` pointers.

The `getUnionType` method in [`internal/checker/utilities.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/utilities.go) (around line 645) handles deduplication and flag computation:

```go
// Building a union type from constituent types
union := c.getUnionType(typeA, typeB) 
// Returns *checker.Type with TypeFlagsUnion set

```

This method automatically computes the resulting type flags and simplifies the union where possible, mirroring TypeScript's union reduction rules.

## Summary

- **typescript-go** implements TypeScript types as native Go structs and constants rather than performing runtime conversion.
- **TypeFlags** and **ObjectFlags** bit masks in [`internal/core/constants.go`](https://github.com/microsoft/typescript-go/blob/main/internal/core/constants.go) provide efficient primitive and object type identification.
- **Literal types** use dedicated structs (`StringLiteralType`, `NumberLiteralType`) to preserve exact values.
- **Generic instantiation** relies on the `TypeMapper` hierarchy in [`internal/checker/mapper.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/mapper.go) for type argument substitution.
- **Union and intersection** types aggregate constituent types via `UnionType` and `IntersectionType` structs managed by checker utilities.

## Frequently Asked Questions

### How does typescript-go represent the TypeScript `any` type in Go?

The `any` type maps to `TypeFlagsAny` combined with an intrinsic type creation. In [`internal/checker/checker.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/checker.go) at line 964, the checker initializes `c.anyType` using `c.newIntrinsicType(core.TypeFlagsAny, "any")`, storing it as a `*Type` with the appropriate bit flag set for fast identification.

### What is the difference between TypeFlags and ObjectFlags in typescript-go?

**TypeFlags** classify primitive and intrinsic types (string, number, any, unknown), while **ObjectFlags** categorize structured types (classes, interfaces, arrays, tuples). A single `*Type` value can carry both flag sets simultaneously, with TypeFlags indicating the general category and ObjectFlags providing specific object subcategories.

### How are generic type arguments substituted during type checking?

Generic substitution uses the **TypeMapper** interface implementers in [`internal/checker/mapper.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/mapper.go). When instantiating a generic, the checker creates a `SimpleTypeMapper` or `ArrayTypeMapper` that maps parameter IDs to concrete argument types, then stores this mapper on the resulting type for lazy resolution during subsequent type operations.

### Where are union types constructed in the typescript-go codebase?

Union type construction occurs primarily in [`internal/checker/utilities.go`](https://github.com/microsoft/typescript-go/blob/main/internal/checker/utilities.go) via the `getUnionType` function. This helper deduplicates constituent types, computes union flags, and returns a `*Type` backed by the `UnionType` struct, ensuring TypeScript's union reduction semantics are preserved in the Go implementation.