I’m a little further ahead in this project than I’d like to be to just start a dev log, but I'm going to do it anyway. Moving forward, I want to treat this as a daily log—a place to dump my thoughts, the hard realities, and the technical pivots of what I'm building.
The project is called tgo (t-G-O). The reason for the name is simple: "tsgo" was already taken by Microsoft when they wanted to create a compiler chain and checker for TypeScript written in Go. When I first heard about their project, I actually thought they were doing what I’m doing—writing TypeScript and producing compiled Go. They aren't. But I am.
And so far, the results are wildly compelling.
If you've built complex systems, you know the cycle. You get real hot on an idea, you go down the rabbit hole, and then you hit a wall. The classic feelings of inadequacy creep in. You start wondering, Is this actually going to work? Will it be good enough? But then there are the moments where you get over the hurdle, look at the output, and go, This shit motherfucking works.
From V1 Chaos to V2 Precision
Right now, we are on version two of the compiler. V1 was basically me just throwing stuff at the wall. It was a rough attempt to create an intermediate representation and write it out as strings. The result? Massive, 5,000-line files. Crazy nested logic. Switch statements and if/else blocks spanning a thousand lines.
To manage this scale of abstract code, I am using AI heavily—but I am strictly controlling the process.
I took all my past experiences in development and decided to anchor this entire project to a rigid Test-Driven Development (TDD) process. I’ve known about TDD my whole career. I’m a massive advocate for unit tests, 100% code coverage, and edge-case testing because I build platforms and libraries that people depend on. But this compiler is different. It is astronomically complex and pretty fucking hard.
Every single inch we move forward is driven by a scenario. We want to implement a new feature, a refactor, or support a new library? We write the scenario first. We run it. We make sure it fails. We look at the converted TypeScript-to-Go output, and then we write the changes. It is the only way to prevent regressions.
The Wins: Speedy as Hell
I am trying to make this compiler output code that is speedy as hell, and the results are already in.
We ran a performance test against standard Node generating UUIDs (calling Node's randomUUID() function a million times). tgo is slower by about 0.1% on pure generation. However, when we take that same test and add a deduplication confirmation to ensure all one million hashes are unique, tgo is an 8x speedup. It is monumentally faster.
To make this work, we’ve actually had to build a Go standard library that effectively replaces the Node/JavaScript standard libraries. I can currently compile the "uuid" library and run it as a package to a Go library, or drop the full source code inside an application as a folder, and the whole thing just works. Validations, UUID v5s, binary operations, arrays, buffers—it works, and it matches external expectations perfectly.
The Hard Engineering Realities
We chose Go primarily because of memory management. I looked at C++, but the lack of a garbage collector meant memory management would become astronomically complicated—effectively requiring me to invent a garbage collector just to handle things like instantiating new objects.
But Go comes with its own limitations. Go doesn't support "OR-ing" on types. It doesn't have JavaScript's version of truthiness (where undefined and null are separate things but work similarly in truthiness evaluations). Go just has a nil concept.
The core philosophy of tgo is this: You are a TypeScript developer. You shouldn't have to care about Go. You write TypeScript, think in TypeScript, and you get the exact same expected results, just running natively in Go.
To pull that off, we're doing deep work on polymorphism. I want to build structs that are generated at compile time with minimal name-mangling so the code remains intelligible. We are aggressively avoiding dynamic types, interfaces, and anys so the compiled Go code stays fast. If the TypeScript inference gets into any territory, it gets boxed into an interface, and it just won't run as fast.
We are constantly hitting limitations—like handling casting (as unknown as)—and we will publish a full list of these limitations. The compiler will eventually warn you as early as possible when you do something that Go fundamentally cannot do.
The Ultimate Vision
Once we clear these major hurdles—like compiling my highly-generic Functional Models library, which has layers of complex type inference—the endgame is clear.
This is for developers who want to write in one language. You write your front end in React. You use the exact same TypeScript libraries, typing, and interfaces for your back end. Then, tgo compiles your back end into ridiculously fast, memory-efficient Go.
But there is a catch. This compiler is going to force you to be a better developer. You have to have good typing. You can't have jacked-up typing where you bypass the TypeScript system. If you try to cheat the compiler, you're going to run into trouble.
We have about 170 tests passing right now. The next major milestone is getting deep polymorphism fully dialed in.
I’ll keep updating this log as we push forward.

