[HN Gopher] Show HN: Zero-codegen, no-compile TypeScript type in...
___________________________________________________________________
Show HN: Zero-codegen, no-compile TypeScript type inference from
Protobufs
Author : 18nleung
Score : 76 points
Date : 2025-04-14 15:41 UTC (7 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| jillyboel wrote:
| Cool, but I assume not great for performance?
|
| Probably better to just stick with codegen
| dtech wrote:
| Assuming you mean compiler/editor performance then yes I assume
| this wrecks it. Shouldn't matter for runtime though.
| jillyboel wrote:
| Right, I meant editor performance. None of the options should
| impact runtime performance anyway.
| 18nleung wrote:
| 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)
| recursive wrote:
| Typescript never generates classes or constructors that
| aren't present in source code. Whether or not constructors
| are present is completely independent from whether you're
| using code gen.
| jillyboel wrote:
| > depending on how your codegen works and how you're using
| protos at runtime, this approach might actually be faster at
| runtime
|
| If your codegen is introducing runtime overhead you should
| use a different codegen.
|
| > type inference in VSCode seemed reasonably fast with the
| toy examples I was playing with
|
| It usually is. It can become a problem in a real project that
| has a _lot_ of stuff going on, though.
| mubou wrote:
| 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.
| 18nleung wrote:
| I would have written a shorter source, but I did not have the
| time.
| sgrove wrote:
| Or even run doom in TypeScript's type system!
| mubou wrote:
| Prepare to have your mind blown:
|
| https://www.youtube.com/watch?v=0mCsluv5FXA
| IshKebab wrote:
| Probably not though because he was clearly referring to
| that.
| throwanem wrote:
| 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.)
| NoTeslaThrow wrote:
| The criticisms were valid then, too. C (including the
| preprocessor of course) is still not fully parseable if you
| include things like token concatenation.
| throwanem wrote:
| I make no representation as to soundness, then or now. Not
| till I figure out where my copy of the UNIX-HATERS Handbook
| has got to, at any rate. I've had cause reasonably recently
| to reread the X and sendmail chapters, not so much this
| one.
| plopz wrote:
| I wish javascript had gone in the same direction as php with
| types.
| rad_gruchalski wrote:
| Which is?
| 1oooqooq wrote:
| literary anything other than ts with it's hacks to half
| assely support multiple signatures that end up crippling
| the whole thing. there's zero type inference anywhere
| unless you specifically import types and manually assign
| everything.
|
| coming from rust, ts has a very high f-meter score
| rad_gruchalski wrote:
| I was hoping to hear how are php types better than TS
| instead of another rant about how Rust is the greatest.
| Anyone?
|
| By the way, having lived in Scala 2 for a few years, Rust
| is half-assed. Type system leaks through the fingers when
| working with async collections. Future.sequence from
| Scala makes great cli apps. Scala collections are a work
| horse. The only thing from Rust I like is the shorthand
| question mark return (compiler magic for Result type).
| spankalee wrote:
| 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.
| mubou wrote:
| I don't disagree! It's just the fact that it has to be
| transpiled to JS that's the problem, because it means none of
| the types are "real"; there's no runtime assurance that a
| string is actually a string. TS is great and I'd never go
| back to JS, but it's ultimately a bandaid. Native TS support
| in browsers is probably never going to happen, though, sadly.
|
| Imagine if WASM were supported natively instead, with
| browsers exposing the same DOM interfaces that they do to JS.
| You could link a wasm binary in a <script> and do everything
| you can with JS/TS, but with any language of your choosing.
| No doubt a compiled form of TS would appear immediately. We'd
| no longer need separate runtime type checking.
|
| Just feels like priorities are in the wrong place.
| merb wrote:
| Wasm gc was needed for that. Wasm evolves slowly so that it
| can be done right. Even if the dom api comes, not a lot of
| it will change since only c-like languages will be as small
| as possible to fit into the space of JavaScript.
| spankalee wrote:
| I think you're conflating cause and effect in several
| cases. TypeScript can't be thought of, and would never
| exist, independently from JavaScript like you're trying to
| do.
|
| TypeScript wasn't created separate from JavaScript and then
| chose JavaScript as a backend. TypeScript only exists to
| perform build-time type checking of JavaScript. There
| wouldn't be a TypeScript that compiled to something else,
| because other languages already have their own type
| systems.
|
| Runtime type-checking isn't part of TypeScript because 1)
| It isn't part of JavaScript, and TypeScript doesn't add
| runtime features anymore. 2) It'd be very expensive for
| simple types, 3) Complex types would be prohibitively
| expense as you have to both reify the types and perform
| deep structural checking.
|
| WASM also is natively supported, and with newer extensions
| like reference types and GC, we're getting closer to the
| point where a DOM API could be defined. It'll still be a
| long while, but that's the long-term direction it's heading
| in. But even then, you would only see a TypeScript-to-WASM
| compiler[1] because there's already so much TypeScript out
| there, not because TypeScript is a particularly good
| language for that environment. A more static language would
| be a lot better for a WASM target.
|
| [1]: Porfor is already such a compiler for JS and TS, but
| it does not do runtime type-checking: https://porffor.dev/
| tim1994 wrote:
| 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?
| throwanem wrote:
| I love this, and I bet the compile errors it produces on
| malformed protobuf are _wild._
| porridgeraisin wrote:
| Cool. Once the linked TS issue is resolved it will be able to
| resolve from files too which is great
| recursive wrote:
| 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.
|
| [1]: https://github.com/microsoft/TypeScript/issues/42219
| cadamsdotcom wrote:
| That can be done with a `sed` call so it's not a new
| dependency.
| ZitchDog wrote:
| 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.
| recursive wrote:
| Not familiar with the capabilities of javac, but in my
| imagination, I'm referring to a tool that runs prior to the
| typescript compiler, that just writes the intended source as
| text. Typescript never knew it wasn't in the repository or
| anything.
| catapart wrote:
| It's true that it's another dependency, but this is the entire
| contents of a file I drop into my project root called `raw-
| loader.d.ts`:
|
| ```
|
| 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.
| spankalee wrote:
| 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.
|
| [1]: https://github.com/microsoft/TypeScript/issues/33304
| aappleby wrote:
| This is both hilarious and awesome. I think the Typescript devs
| are just showing off at this point. :D
| meindnoch wrote:
| Looks like TypeScript envies Swift's compile times.
| pragma_x wrote:
| 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.
| catapart wrote:
| Very cool work!
|
| 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.
| mherkender wrote:
| 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.
| jitl wrote:
| 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.
| tantalor wrote:
| What do you use to go from ts->pb?
| mifydev wrote:
| 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.
___________________________________________________________________
(page generated 2025-04-14 23:00 UTC)