The fact that the source is so small is wild. I would have expected a huge convoluted parsing library implemented in types.
On the other hand, the fact that this is even possible is more wild. Instead of replacing JS with a proper statically-typed language, we're spending all this effort turning a preprocessor's type system into a turing-complete metalanguage. Pretty soon we'll be able to compile TypeScript entirely using types.
TypeScript does an amazing job at describing the types of real-world JavaScript. It's incredibly good, and very useful, even in the face of extremely dynamic programs. The fact that it can describe transforms of types, like "this is a utility that adds an `xxx` prefix to every property name" is frankly unparalleled in mainstream languages, but more importantly lets us describe patterns that come up in real-world JS programs - it's not fluff!
And luckily, the most complex of types are usually limited to and contained within library type definitions. They add a lot of value for the library users, who usually don't have to deal that that level of complexity.
People have fussed the same of the C preprocessor, around the same time I and maybe you were born. (There's a pretty good chance I'm your parents' age, and nearly no chance you're the age of mine.)
This would be even nicer if TypeScript added type inference for tagged template literals, like in this issue [1]. Then you could write:
const schema = proto`
syntax = "proto3";
message Person { ... }
`;
type Person = typeof schema['Person'];
And you could get built-in schema validation with a sophisticated enough type definition for `proto`, nice syntax highlighting in many tools with a nested grammar.
We would love to see this feature in TypeScript to be able to have type-safe template in lit-html without an external tool.
The issue hasn't seen much activity lately, but it would be good to highlight this library as another use case.
It’s pretty rad how flexible template literal types are, but I can’t imagine wanting this kind of shenanigans hanging out in a production app slowing down compile times. I prefer to define types in TypeScript and generate proto from that, since the TypeScript type system is so much more powerful than the Protobuf system. Types are much more composable in TS.
This is kinda why I hate advanced type systems, they slowly become their own language.
"No compile/no codegen" sounds nice until you get slow compile times because a type system is slow VM, the error messages are so confusing it's hard to tell what's going on, and there's no debugging tools.
What's kind of amazing is that Typescript's matching of strings through the type system converges on a first-class PEG in a few places (see string.ts). The rest of the library is really damn succinct for how much lifting it's doing.
My hat's off to the author - I attempted something like this for a toy regex engine and got nowhere fast. This is a much better illustration of what I thought _should_ be possible, but I couldn't quite wrap my head around the use of the ternary operator to resolve types.
You're right that IDE/dev-time performance might be slower than using generated types since this relies on "dynamic" TypeScript inference rather than static codegen'd types.
That said, depending on how your codegen works and how you're using protos at runtime, this approach might actually be faster at runtime. Types are stripped at compile-time and there’s no generated class or constructor logic — in the compiled output, you're left with plain JS objects which potentially avoids the serialization or class overhead that some proto codegen tools introduce.
(FWIW, type inference in VSCode seemed reasonably fast with the toy examples I was playing with)
This is super cool — love the zero-codegen approach. I’ve had to deal with codegen hell in monorepos where a tiny .proto change breaks half the pipeline. Curious how this handles more complex types like nested messages or oneof fields?
Also, been building something in a different space (LeetCode prep tool), but the idea of removing build steps for dev speed really resonates. Would love to see how this could plug into a lightweight frontend setup.
This requires the whole `.proto` declaration inline in source a string constant. I'm not holding my breath on "Import non-js content"[1] getting approved, so that means you still have to use another build dependency, or manually keep the .proto files synchronized across multiple sources truth. In that light, it's not clear when this would be a benefit over straight-forward code gen. Cool POC hack though.
Then, when I add the file to my types property array of my tsconfig's compilerOptions, I can import anything I want into a typescript file as a string, so long as I add "?raw" to the end of it. I use it to inject HTML and CSS into templates. No reason it couldn't be used to inject a .proto file's contents into the inline template.
Again, you're technically correct! But a "import non js content" feature is a pretty solveable problem in TS. Maybe not at the language level, but at the implementation level, at least.
The problem is that TypeScript is terrible at codegen, there are no standard extension points like we have with javac and others. So we are forced to do these crazy hacks at the type level rather than just generating types as you would in other languages.
This makes me wonder if this the way to do schema generation in Typescript. I’m working on Typeconf, and we have a separate step for translating Typespec schema to Typescript, it’ll be cool if we could just load typespec directly.
It's always impressive how far people can take TypeScript and even build parsers with it. But this is limited to inlined string literals and cannot read files (a TS limitation).
I wonder if the author has a use case in mind for this that I don't see. Like if you are only using TS, what's the point of protobuf? If you are exchanging data with programs written in other languages why avoid the protobuf tooling that you need anyway?
Maybe this is just a fun toy project to write a parser in TS?
mubou|10 months ago
On the other hand, the fact that this is even possible is more wild. Instead of replacing JS with a proper statically-typed language, we're spending all this effort turning a preprocessor's type system into a turing-complete metalanguage. Pretty soon we'll be able to compile TypeScript entirely using types.
spankalee|10 months ago
And luckily, the most complex of types are usually limited to and contained within library type definitions. They add a lot of value for the library users, who usually don't have to deal that that level of complexity.
sgrove|10 months ago
18nleung|10 months ago
throwanem|10 months ago
sandreas|10 months ago
A fun read / Video...
plopz|10 months ago
spankalee|10 months ago
We would love to see this feature in TypeScript to be able to have type-safe template in lit-html without an external tool.
The issue hasn't seen much activity lately, but it would be good to highlight this library as another use case.
[1]: https://github.com/microsoft/TypeScript/issues/33304
unknown|10 months ago
[deleted]
jitl|10 months ago
h1fra|10 months ago
tantalor|10 months ago
mherkender|10 months ago
"No compile/no codegen" sounds nice until you get slow compile times because a type system is slow VM, the error messages are so confusing it's hard to tell what's going on, and there's no debugging tools.
throwanem|10 months ago
pragma_x|10 months ago
My hat's off to the author - I attempted something like this for a toy regex engine and got nowhere fast. This is a much better illustration of what I thought _should_ be possible, but I couldn't quite wrap my head around the use of the ternary operator to resolve types.
jillyboel|10 months ago
Probably better to just stick with codegen
18nleung|10 months ago
That said, depending on how your codegen works and how you're using protos at runtime, this approach might actually be faster at runtime. Types are stripped at compile-time and there’s no generated class or constructor logic — in the compiled output, you're left with plain JS objects which potentially avoids the serialization or class overhead that some proto codegen tools introduce.
(FWIW, type inference in VSCode seemed reasonably fast with the toy examples I was playing with)
dtech|10 months ago
aappleby|10 months ago
anjandutta|10 months ago
Also, been building something in a different space (LeetCode prep tool), but the idea of removing build steps for dev speed really resonates. Would love to see how this could plug into a lightweight frontend setup.
recursive|10 months ago
[1]: https://github.com/microsoft/TypeScript/issues/42219
catapart|10 months ago
```
declare module '*?raw' { const rawFileContent: string export default rawFileContent }
```
Then, when I add the file to my types property array of my tsconfig's compilerOptions, I can import anything I want into a typescript file as a string, so long as I add "?raw" to the end of it. I use it to inject HTML and CSS into templates. No reason it couldn't be used to inject a .proto file's contents into the inline template.
Again, you're technically correct! But a "import non js content" feature is a pretty solveable problem in TS. Maybe not at the language level, but at the implementation level, at least.
yencabulator|10 months ago
Might as well do code generation at that point, it'd even be debuggable.
ZitchDog|10 months ago
cadamsdotcom|10 months ago
mifydev|10 months ago
meindnoch|10 months ago
catapart|10 months ago
Also, I hope you expected me to read that output in the same cadence as the Hooli focus groups, because that's exactly what I did.
porridgeraisin|10 months ago
tim1994|10 months ago
I wonder if the author has a use case in mind for this that I don't see. Like if you are only using TS, what's the point of protobuf? If you are exchanging data with programs written in other languages why avoid the protobuf tooling that you need anyway?
Maybe this is just a fun toy project to write a parser in TS?
nikolayasdf123|10 months ago
unknown|10 months ago
[deleted]