A little while ago, I asked on Twitter whether someone would be interested in reading about how we generate types from our .Net backend to be used in our TypeScript client. So, here we are.
I’ll cover the following topics:
- Why do we even bother?
- Generating TypeScript constants from .Net constants
- Finding the types used in communication between the .Net backend and the TypeScript client
- Generating TypeScript classes from .Net types
- Generating Angular Services from .Net WebApi Controllers
- TypeScript-friendly JSON serialization of F# types
- Testing JSON serialization and deserialization
- Putting all the parts together
Thesw blog posts will likely become more of documentation for ourselves, but I hope you get the main ideas and can build your own solution if you find the approach worthwhile.
Our client is written with TypeScript and Angular. Our backend is written in .Net and uses WebApi. When we started, we wrote the whole backend in C#. In Mai 2020, we started to write new functionality in F#. So we have a mix of C# and F# on the backend.
We refactor code a lot. Either to make it simpler to understand or to make adding new functionality easier. A lot of refactoring in the backend has the consequence that semantically shared types with the client change: names change, and structures change. Keeping the client in a working state is really hard.
We use typed languages because the compiler can help us find errors resulting from such changes. But we don’t have the same compiler in the backend (.Net) and the client (TypeScript/Angular). But if we could generate the TypeScript types automatically from our .Net types, the TypeScript/Angular compiler could help us find errors introduced by refactoring.
Additionally, we want to have TypeScript types compatible with the JSON generated when serializing our .Net types and vice-versa.
Why not simply use Swagger?
We did, but we never were happy with it. Unfortunately, we can’t remember why anymore. There are some vague memories that Swagger was very slow, and we didn’t get it working in a way that the JSON we serialized matched the generated types.
Some additional thoughts
The code that you will see is written in a way that is not unit-testable, it is slow and not very pretty. That is okay for these code generators because we check the resulting artefacts for correctness with the Angular compiler and it is fast and maintainable enough.
In the next post, I’ll show you how we generate constants that need to be shared.
This blog post is made possible with the support of Time Rocket, the product this blog post is about. Take a look (German only).