How to Exclude Specific Go Fields from TypeScript Generation in tsgo
Add a json:"-" or tsgo:"-" struct tag to any exported Go field to prevent it from appearing in the generated TypeScript declarations.
The tsgo command-line tool in the microsoft/typescript-go repository walks your Go AST and converts exported struct fields into TypeScript interface members. When you need to hide specific fields from the resulting .d.ts output—such as sensitive data or internal implementation details—struct tags provide the control mechanism without modifying field visibility in Go.
How Field Visibility Maps to TypeScript Output
The generator follows the same visibility rules as the Go JSON encoder when deciding which fields appear in the output. In internal/transformers/tstransforms/typeeraser.go, the AST walker checks each struct field against these criteria:
- Exported fields (starting with uppercase letter): Included by default
- Unexported fields (starting with lowercase letter): Automatically excluded
- Exported fields with omission tags: Excluded when tagged with
json:"-"ortsgo:"-"
This means any exported field you mark with a dash (-) as the first option in its tag will be skipped during TypeScript generation.
Methods to Exclude Go Fields from TypeScript Output
You have two primary tag-based approaches to suppress field emission, depending on whether you want to affect JSON marshaling simultaneously.
Using the Standard json:"-" Tag
The most common method reuses the standard Go JSON omit marker. When tsgo encounters json:"-", it interprets this as a universal "do not emit this field" signal across all external representations.
package model
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Password string `json:"-"` // Excluded from .d.ts output
}
Using the Custom tsgo:"-" Tag
For cases where you want to hide a field only from TypeScript declarations while keeping it in JSON output, use the tsgo tag. The generator specifically checks for a tag named tsgo and treats - as the omit marker.
type Config struct {
Host string `json:"host"`
DebugMode bool `tsgo:"-"` // Hidden from TypeScript, visible in Go
}
Practical Code Examples
Here is a complete example showing multiple exclusion patterns in a single struct:
package model
import "time"
// User represents a system user with selective TypeScript exposure.
type User struct {
ID int `json:"id"` // → id: number;
Name string `json:"name"` // → name: string;
Email string `json:"email"` // → email: string;
Password string `json:"-"` // **Excluded** from .d.ts
InternalKey string `tsgo:"-"` // **Excluded** from .d.ts only
CreatedAt time.Time `json:"created_at"` // → created_at: Date;
}
Running tsgo (or go run ./cmd/tsgo) on this package produces:
export interface User {
id: number;
name: string;
email: string;
created_at: Date;
}
Notice that both Password and InternalKey are absent from the generated interface.
Advanced Tag Combinations
You can combine tags to fine-tune behavior across JSON serialization and TypeScript generation.
Keeping JSON but Hiding TypeScript
Use both tags when you want a field included in JSON payloads but omitted from type declarations:
type Session struct {
Token string `json:"token" tsgo:"-"` // In JSON, hidden from .d.ts
ExpiresAt int64 `json:"expires_at"`
}
Renaming While Preserving Other Fields
If you need to rename a field for TypeScript while excluding others, provide the desired name in the primary tag:
type Event struct {
RawData []byte `tsgo:"-"` // Completely hidden
Timestamp int64 `json:"eventTime"` // → eventTime: number;
}
Implementation Details in the Source Code
The exclusion logic resides in internal/transformers/tstransforms/typeeraser.go, which walks the Go AST and determines which members to preserve for the declaration file. The code checks struct tags for the omission marker - and filters accordingly.
Additional relevant files in the generation pipeline include:
cmd/tsgo/main.go: Entry point that initiates the transformation pipelineinternal/tsoptions/parsedcommandline.go: Handles the--outputDtsflag that specifies where to write the.d.tsfileinternal/transformers/utilities.go: Provides helper functions likeIsGeneratedIdentifierused during emission
Summary
- Unexported fields (lowercase) are automatically excluded from TypeScript generation
- Add
json:"-"to exclude a field from both JSON and TypeScript output - Add
tsgo:"-"to exclude a field only from TypeScript declarations while preserving JSON behavior - Combine tags (
json:"name" tsgo:"-") to include data in JSON payloads but hide types from consumers - The logic is implemented in
internal/transformers/tstransforms/typeeraser.gofollowing Go's JSON encoding conventions
Frequently Asked Questions
Can I exclude a field from TypeScript but include it in JSON output?
Yes. Use the tsgo:"-" tag without a json:"-" tag. This hides the field from the generated .d.ts file while allowing standard JSON marshaling to include the field in API responses.
Why does json:"-" affect TypeScript generation?
The tsgo generator reuses Go's JSON tagging logic to determine external field names. When the JSON tag is exactly -, the field is considered ignored for any external representation, so tsgo follows that convention for its own output as implemented in internal/transformers/tstransforms/typeeraser.go.
Do I need to use both json:"-" and tsgo:"-" tags?
No. Either tag will exclude the field from TypeScript declarations. Use json:"-" when you want to suppress both JSON serialization and TypeScript generation. Use tsgo:"-" when you need the field in JSON but hidden from TypeScript consumers.
How do I exclude multiple fields from the same struct?
Apply the exclusion tag to each field individually. There is no struct-level exclusion mechanism; you must tag each field you want to hide with either json:"-" or tsgo:"-".
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 →