[HN Gopher] TypeScript please give us reflection/runtime types
       ___________________________________________________________________
        
       TypeScript please give us reflection/runtime types
        
       Author : decs
       Score  : 303 points
       Date   : 2023-07-07 19:36 UTC (1 days ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | dontlaugh wrote:
       | Maybe controversial, but I think code generation is fine. It work
       | well enough in Go or C#.
        
       | vbezhenar wrote:
       | The one downside of this proposal is faster typescript processors
       | like esbuild. Right now they don't care about types, they just
       | strip them from the code. It allows them to be very fast and
       | provide fast feedback loop.
       | 
       | With this proposal those tools must become extremely more
       | complicated and probably they will just be as slow as tsc.
        
         | [deleted]
        
       | shadowgovt wrote:
       | Normally I'd say "hard pass." I'm pretty comfortable with static
       | types being a model where the compiler throws the type
       | information away at compile time, so I can type with abandon
       | without worrying that I'm going to impact runtime performance in
       | my generated code.
       | 
       | ... TypeScript may be one exception to my rule of thumb. It's
       | already compiling down to JavaScript, so you're already paying a
       | performance tax in having your code run in an interpreted
       | language. The question should be "how much more of a performance
       | tax are you paying annotating things with type runtime metadata?"
        
         | mrkeen wrote:
         | Why not just let the compiler build the deserialiser out of the
         | runtime information during compile time, and then throw out all
         | the types?
        
       | thanksgiving wrote:
       | I'm not an expert or anything but I sincerely feel like this is
       | barking up the wrong tree.
       | 
       | To anyone who works on typescript/JavaScript outside the context
       | of a web browser, you DO NOT matter as far as I am concerned. If
       | I was in control of JavaScript/typescript, I'd give zero
       | attention to your demands. You are not my top priority. Go away.
       | 
       | I feel like we are losing focus here. Should JavaScript be an all
       | purpose language? Yes. Should we focus on making a web browser
       | context, also yes.
       | 
       | The reason I led with this is that I think it is up to the
       | JavaScript folks and the web browser vendors to include support
       | for this before typescript can change what it emits. Ideally, I'd
       | say wait a couple of years after browser vendors include support
       | to implement this in typescript.
        
         | Eric_WVGG wrote:
         | I don't understand this comment at all. I mostly work on
         | client-side front-end and am absolutely desperate for better
         | type generation. Zod is making me want to jump out a window
         | right now.
        
           | thanksgiving wrote:
           | My comment is simple. Don't add anything to JavaScript if it
           | does not help in the context of a web browser. Don't add
           | anything to typescript emitted output if it isn't in
           | JavaScript.
        
           | colinmcd wrote:
           | Something like typebox (that's designed to map one-to-one
           | onto JSON Schema) may be better if codegen is a priority.
        
       | klysm wrote:
       | So this is asking for a completely different language?
        
       | RussBrown00 wrote:
       | unpopular opinion, but this just fosters my opinion that TS
       | people just don't understand JS at all. I wish TS would just die
       | (another currently unpopular opinion). If you want runtime type
       | safety, go use a different language and stop trying to ruin JS,
       | it's already the messed up crazy cousin and it doesn't need to be
       | in-bread anymore, it's perfect the way it is!
        
         | imbnwa wrote:
         | Only writer I know who discusses pure JS patterns that embrace
         | those its dynamism is Raganwald Braithwaite[0]. For example,
         | most people I know would call this hacky code[1], when this is
         | just design patterns in idiomatic, non-Java/C#-constrained
         | JavaScript. The truth, most devs desire intellisense and/or
         | theorycrafting that comes with static types and compilers.
         | 
         | [0]https://raganwald.com/
         | 
         | [1]https://raganwald.com/2014/04/10/mixins-forwarding-
         | delegatio...
        
       | DanRosenwasser wrote:
       | Hey all, TypeScript PM here.
       | 
       | I understand the desire here. Runtime type checking is often
       | necessary for data validation, and we can see lots of libraries
       | developed to help fill the gap here. But I think the fact that
       | there are so many libraries with different design decisions is
       | pretty indicative that this is not a solved problem with an
       | obvious solution. We knew this going into the early design of
       | TypeScript, and it's a principle that's held up very well.
       | 
       | What have been happy to find is that we've grown TypeScript to be
       | powerful enough to communicate precisely what runtime type-
       | checking libraries are actually doing, so that we can derive the
       | types directly. The dual of this is that people have the tools
       | they need to build up runtime type validation logic out of types
       | by using our APIs. That feels like a reasonable level of
       | flexibility.
        
         | 0xb0565e487 wrote:
         | I'm relatively new to programming and had a question about
         | TypeScript's functionality. Is there any specific reason why
         | TypeScript doesn't allow for the creation of custom and
         | intricate data types? For example, I'm unable to define a
         | number type within a specific range, or a string that adheres
         | to a certain pattern (like a postal code).
         | 
         | I'm imagining a language where I could define a custom data
         | type with a regular function. For instance, I could have a
         | method that the compiler would use to verify the validity of
         | what I input, as shown below:
         | 
         | function PercentType(value: number) { if (value > 100 || value
         | < 0) throw new Error();                   return true;
         | 
         | }
         | 
         | Is the lack of such a feature in TypeScript (or any language) a
         | deliberate design decision to avoid unnecessary complexity, or
         | due to technical constraints such as performance
         | considerations?
        
           | lolinder wrote:
           | TypeScript actually does have some support for the kinds of
           | types you're suggesting. For example, a US postal code can be
           | defined like so:                   type PostalCode =
           | `${Digit}${Digit}${Digit}${Digit}${Digit}`;              type
           | Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' |
           | '9';
           | 
           | You could trivially define a `parsePostalCode` function that
           | accepts a string and yields a PostalCode (or throws an error
           | if it's the wrong format).
           | 
           | Ranges like percent are much trickier--TypeScript would need
           | to compute the return type of `Percent + Percent` (0 <= T <=
           | 200), `Percent / Percent` (indeterminate because of division
           | by zero or near-zero values), and so on for all the main
           | operators. In the best case scenario this computation is very
           | expensive and complicates the compiler, but in the worst case
           | there's no clear correct answer for all use cases (should we
           | just return `number` for percent division or should we return
           | `[0, Infinity]`?).
           | 
           | In most mainstream programming languages the solution to this
           | problem is to define a class that enforces the invariants
           | that you care about--Percent would be a class that defines
           | only the operators you need (do you really need to divide
           | Percent by Percent?) and that throws an exception if it's
           | constructed with an invalid value.
        
           | n2d4 wrote:
           | _> Is the lack of such a feature in TypeScript (or any
           | language) a deliberate design decision to avoid unnecessary
           | complexity, or due to technical constraints such as
           | performance considerations?_
           | 
           | It makes a lot of things impossible. For example, if you
           | defined two different types of ranges, OneToFifty and
           | OneToHundred similarly to your PercentType above, the
           | following code would be problematic:                   let x:
           | OneToFifty = <...>;         let y: OneToHundred = <...>;
           | y = x;
           | 
           | Any human programmer would say the third line makes sense
           | because every OneToFifty number is also OneToHundred. But for
           | a compiler, that's impossible to determine because JavaScript
           | code is Turing-complete, and so it can't generally say that
           | one is certainly a subset of the other.
           | 
           | In other words, any two custom-defined types like that would
           | be unassignable from and to each other, making the language
           | much less usable. Now add generics, co-/contravariance, type
           | deduction, etc., and suddenly it becomes clear how much work
           | adding a new type to the type system is; much more than just
           | a boolean function.
           | 
           | That said, TypeScript has a lot of primitives, for example,
           | template string types for five-digit zip codes:
           | type Digit = '0' | '1' | '2' | '3' | <...> | '9';
           | type FiveDigitZipCode =
           | `${Digit}${Digit}${Digit}${Digit}${Digit}`;
           | 
           | (Actually, some of these are Turing-complete too, which means
           | type-checking will sometimes fail, but those cases are rare
           | enough for the TS team to deem the tradeoff worth.)
        
             | 0xb0565e487 wrote:
             | Thanks :)
        
             | jerf wrote:
             | It's the fundamental programming language design conundrum:
             | Every programming language feature looks easy in isolation,
             | but once you start composing it with everything else, they
             | get hard. And hardly anything composes as complexly as
             | programming languages.
             | 
             | There's sort of a meme where you should never ask why
             | someone doesn't "just" do something, and of all the people
             | you shouldn't ask that of, programming language designers
             | are way, way up there. Every feature interacts not just
             | with itself, not just with every other feature in the
             | language, but also in every other possible combination of
             | those features at arbitrary levels of complexity, and you
             | can be assured that someone, somewhere out there is using
             | that exact combination, either deliberately for some
             | purpose, or without even realizing it.
        
           | bern4444 wrote:
           | Some of this is possible in the type system like a range:
           | From stackoverflow:
           | https://stackoverflow.com/questions/39494689/is-it-
           | possible-...                 type Enumerate<N extends number,
           | Acc extends number[] = []> = Acc['length'] extends N
           | ? Acc[number]         : Enumerate<N, [...Acc, Acc['length']]>
           | type NumberRange<F extends number, T extends number> =
           | Exclude<Enumerate<T>, Enumerate<F>>            type
           | ZeroToOneHundred = NumberRange<0, 100>
           | 
           | One limitation is that this has to be bounded on both ends so
           | constructing a type for something like GreaterThanZero is not
           | possible.
           | 
           | Similarly for zip codes you could create a union of all
           | possible zip codes like this:                 type USZipCodes
           | = '90210' | ...
           | 
           | Often with the idea you have in mind the solution is to
           | implement an object where the constructor does a run time
           | check of the requirements and if the checks pass instantiate
           | the instance and otherwise throw a run time error.
           | 
           | In functional programming this is often handled with the
           | Option which can be thought of as an array with exactly 0 or
           | 1 elements always. 0 elements when a constraint is not met
           | and 1 element when all constraints are met.
           | 
           | This [0] is a library I wrote for JS/TS that provides an
           | implementation of Options. Many others exist and other
           | languages like Rust and Scala support the Option data
           | structure natively.
           | 
           | [0] https://github.com/sbernheim4/excoptional
        
             | 0xb0565e487 wrote:
             | Interesting, thanks!
        
           | hn_throwaway_99 wrote:
           | > or a string that adheres to a certain pattern (like a
           | postal code).
           | 
           | This is somewhat supported with template literal types,
           | https://www.typescriptlang.org/docs/handbook/2/template-
           | lite.... However, there are good technical/performance
           | reasons they don't support, for example, plain regexes -
           | there is a HUGE discussion on this topic here,
           | https://github.com/microsoft/TypeScript/issues/6579.
        
           | wk_end wrote:
           | This is a feature some (experimental) programming languages
           | have - look into dependent types. The long-and-short of it is
           | that it adds a lot of power, but comes at an ergonomic cost -
           | the more your types say about your code, the more the type
           | checker needs to be able to understand and reason about your
           | code, and you start to run up against some fundamental limits
           | of computation unless you start making trade-offs: giving up
           | Turing-completeness, writing proofs for the type checker,
           | stuff like that.
           | 
           | Another interesting point of reference are "refinement
           | types", which allow you to specify things like ranges to
           | "refine" a type; the various constraints are then run through
           | a kind of automated reasoning system called an SMT solver to
           | ensure they're all compatible with each other.
        
             | 0xb0565e487 wrote:
             | Awesome, thanks for the pointers!
        
           | golergka wrote:
           | You can do exactly this with io-ts and fp-ts: https://gist.gi
           | thub.com/golergka/64b06f711e4cb07c67367bdace7...
        
         | fouc wrote:
         | thoughts on the other poster asking for type info to be kept
         | around in the Class objects after compilation?
        
         | scotty79 wrote:
         | Maybe official preprocessor plugins for TypeScript compiler
         | could help?
         | 
         | I understand that everybody who needs it can already put their
         | own preprocessor that generates runtime objects from type
         | information before the code is passed to tsc for compilation.
         | 
         | But the effort is inconsistent and distributed.
         | 
         | If TypeScript officially supported pluggable preprocessor and
         | plugin ecosystem for it some good solutions might get
         | discovered.
        
           | andix wrote:
           | What's next? An official TypeScript UI framework, will it be
           | Vue, React, Next.js or Svelte? An official TypeScript date
           | library?
        
             | scotty79 wrote:
             | What's the point of any of those?
             | 
             | Generating code based on type annotations is frequently
             | requested feature directly related to the core feature of
             | TypeScript which is type system.
        
             | pjmlp wrote:
             | This is the curse of guest languages, after the initial
             | adoption pain everyone wants idiomatic libraries and
             | pretends the underlying platform doesn't exist.
             | 
             | Until they hit a roadblock caused by a leaky abstraction,
             | that proves them otherwise.
        
               | andix wrote:
               | Type script does a very good job not to hide the
               | underlying platform. In it's essence it is just a
               | development time linter and does not interfere with the
               | JavaScript runtime at all (except enums).
               | 
               | And I think that's actually the reason why it won the
               | competition against Googles Dart. They even used
               | Microsofts TypeScript for Angular instead of their own
               | language Dart.
        
               | pjmlp wrote:
               | Indeed, and that is why the Typescript team is against
               | any feature that steps away from that relationship.
        
             | clansimus wrote:
             | I'll take an official WYSIWYG editor while we're at it
        
         | mirekrusin wrote:
         | Microsoft hosted MacroScript as TypeScript plugin or toplevel
         | wrapper would solve this problem.
         | 
         | You just need to spark it, community will help maintaining it.
         | 
         | It would solve all codegen needs from generating clients to
         | runtime type assertions and many interesting problems in
         | between.
        
       | gizmolo wrote:
       | Future ECMAScript iterations will include types and then
       | hopefully TypeScript can take advantage of that to implement
       | reflection and other cool things
        
       | MrResearcher wrote:
       | Typescript already kind of has it, it's just they got it
       | backwards.
       | 
       | One needs to define their types as a const, like this one:
       | 
       | ``` [{ type: Number, name: "field1" }, { type: String, name:
       | "field2" }] as const ```
       | 
       | and then use Typescript magic to convert it into the fully
       | fledged Typescript type.
       | 
       | Yes, it's annoying, but it's more flexible.
        
         | epolanski wrote:
         | This is as useful as vue 2's prop types: very little.
        
         | gloryjulio wrote:
         | U just need a library to enable this to reduce the boilerplate.
         | I don't see how that's impossible
        
         | asherah wrote:
         | this wouldn't work for interfaces, or more complicated types
        
       | noobdev9000 wrote:
       | Modern TS code is hard for me to read and reason, and I use Rust,
       | Haskell, C++. Way too complex for my brain
        
         | epolanski wrote:
         | Well, as always, this really depends on our the code we read
         | and our background.
         | 
         | TypeScript's type system is indeed way more verbose than
         | Haskell's.
        
       | chmod775 wrote:
       | Since it's not explicitly listed there, I feel I should shout out
       | David Blass and his incredibly cool ArkType project[1]. It's
       | typescript wizardry.
       | 
       | He sometimes (used to?) streams himself working on twitch and
       | it's a really comfy place to hang out.[2]
       | 
       | [1] https://github.com/arktypeio/arktype
       | 
       | [2] https://www.twitch.tv/arktypeio
        
         | yewenjie wrote:
         | How complete is arktype actually? The README says a lot of the
         | syntax is yet to be developed, and don't even get me started on
         | the horror of the docs site.
        
           | chmod775 wrote:
           | Until a short while ago it was still very much work in
           | progress.
           | 
           | Right now a lot of work seems to be going into getting a 1.0
           | release out of the door (the current one is still marked
           | alpha).
        
       | BiteCode_dev wrote:
       | While type hints in Python are not as nice as typescript
       | annotations, I understand their plea, because once thing Python
       | does better is runtime introspection.
       | 
       | Which means we can have dataclass, pydantic, typer and fastapi
       | all generating their stuff from regular type hints. No need for
       | special syntax or functions. And that's super nice.
        
       | orthecreedence wrote:
       | Reflection on a language that compiles to javascript? I don't get
       | it. Why are people so allergic to macros?? Every stinking
       | language that has compiled to JS has had a chance to do macros
       | but they don't. Coming from many years spent in the lisp world,
       | metaprogramming is this incredible feature that, in my
       | experience, completely negates the need for runtime reflection
       | while adding many other possibilities as well. I get it...the
       | syntax is way harder when your language isn't basically a pre-
       | parsed AST. But rust does it.
       | 
       | Seems like a huge waste.
        
         | kazinator wrote:
         | TypeScript imposes more detailed typing onto JS objects. It
         | makes sense to ask the question: can the type imposed by TS
         | onto a JS object be reified as a run-time object?
         | 
         | It could be, but maybe the use cases for that can be solved in
         | another way that don't require the type system at run-time.
         | 
         | The good news is that static type is, well, static. All the
         | objects of the same type can share a pointer to the same type
         | metadata. The overhead is thus not necessarily huge: one extra
         | property to initialize when an object is created.
         | 
         | The generated TS code has to carry the run-time support
         | routines for the type stuff though.
        
         | tinideiznaimnou wrote:
         | Preach, brother!
         | 
         | If only ECMAScript had a native macro system, TypeScript could
         | be just a library - and I would have zero problems with its
         | existence.
         | 
         | You're probably familiar with the following anecdote:
         | 
         | >Eich originally joined intending to put Scheme "in the
         | browser",[4] but his Netscape superiors insisted that the
         | language's syntax resemble that of Java.
         | 
         | JavaScript became the language that we all love to hate due to
         | political, not technical reasons. Yet people look at me funny
         | when I call out the TS/React monoculture as the blatant
         | corporate power grab that it is.
        
           | kazinator wrote:
           | If ECMAScript had macros such that TypeScript could be a
           | library, people would still ask the question: can we attach
           | the type object manipulated by the library to the objects?
           | 
           | If ECMAScript had macros, page load times would skyrocket.
           | ECMAScript and/or browsers would have to define a way to
           | distinguish JS-with-macros files and embedded scripts from
           | plain old JS that doesn't require expansion.
           | 
           | Any JS code bases with complicated macros that take time and
           | memory to expand would have to be expanded by the developer
           | and shipped expanded. So, back to the same model as
           | TypeScript.
        
             | tinideiznaimnou wrote:
             | You raise fair points.
             | 
             | >So, back to the same model as TypeScript.
             | 
             | I beg to differ. There's a world of difference between:
             | 
             | 1. a standardized _feature_ with an official spec, which is
             | subject to debate among the community, and of which it 's
             | viable to have multiple competing implementations; vs
             | 
             | 2. a proprietary _product_ that presents itself to be a
             | superset of the core language (but isn 't), is peddled by a
             | single multinational, has a single implementation designed
             | by an unaccountable elite in the employ of said
             | multinational, which just so happens to be the original
             | Dumbing Down The Computer Company
             | 
             | >If ECMAScript had macros, page load times would skyrocket.
             | 
             | >ECMAScript and/or browsers would have to define a way to
             | distinguish JS-with-macros files and embedded scripts from
             | plain old JS that doesn't require expansion.
             | 
             | If you introduce them today by way of a polyfill, maybe.
             | I'm not necessarily advocating for introducing native
             | macros to ECMA-262 at the present juncture. But I can't
             | help speculating what would've happened if they had caught
             | on.
             | 
             | If they were introduced at the point in history when people
             | were first realizing transpilers were a thing; or designed
             | into the language from the start; or a pre-existing
             | metaprogramming-aware language was used in browsers,
             | instead of Eich designing in 10 days an entire new language
             | under the constraint that it also has to be an ad for Java
             | - who knows where we would be as a civilization? What do
             | you think?
        
         | vbezhenar wrote:
         | What're you talking about? JS has had macros since the dawn of
         | this world. Just eval(anything). For example eval(tsc("function
         | f(x: number): number { return x + 1}")). Easy!
        
       | eyelidlessness wrote:
       | This comes up so often, and every time I wonder how much the
       | people who want it have a shared understanding of what it is they
       | want. I realize this is reiterating a point that TS team members
       | have already made, but I'm coming from a different perspective:
       | actually having built higher level tooling on top of one of the
       | solutions mentioned in the post, and having built a fairly mature
       | prototype of another solution from the ground up to address
       | problems none of the existing offerings solve.
       | 
       | My use case isn't particularly outlandish, I can even imagine it
       | being non-niche if I ever get around to publishing it. But it's
       | also pretty far afield from any of the existing solutions:
       | platform-agnostic documentation as a core/foundational principle.
       | 
       | My original work implemented JSON Schema documentation on top of
       | io-ts, and added some runtime and type level functionality to
       | support that. But my vision for a hypothetical successor is that
       | 
       | - the documentation standard itself (whether JSON Schema,
       | OpenAPI, or any other underlying format) should be the underlying
       | primitive
       | 
       | - the underlying format should be composable to produce APIs
       | which are just as user friendly (ie users shouldn't have to muck
       | around with the doc format unless they have a really specific use
       | case, and even then they should still be able to compose the
       | parts they're not concerned with)
       | 
       | - no additional build time codegen tooling: define a schema once,
       | its type is inferrable from the definition without a compiler
       | extension or IDE config, its documentation is a plain function
       | call executable in any standard runtime to resolve what's
       | composed
       | 
       | This is all very achievable in TypeScript as-is. But it's way out
       | of scope from what I imagine any first class thing would or
       | should be. And sure, if such first class thing existed, that
       | wouldn't make my thing any less achievable. But here's what I
       | think it would do:
       | 
       | 1. Disincentivize usage by users who prefer the first class thing
       | with type syntax as the primary authoring mechanism.
       | 
       | 2. Incentivize me to cave on tooling to accommodate that.
       | 
       | 3. Piss people off because "we wanted less tooling not more".
       | 
       | 4. Recurse into this same debate.
       | 
       | I'd personally prefer the status quo. Even if that means
       | rehashing the same debate every few months, at least it's at a
       | recursion depth that's manageable and doesn't have countless
       | other sets of unintended consequences.
        
       | paulddraper wrote:
       | Better title: TypeScript please give us reflection/runtime types
       | 
       | AFAIK the best current solution is emitlDecoratorMetadata. [1]
       | 
       | [1]
       | https://www.typescriptlang.org/tsconfig#emitDecoratorMetadat...
        
         | dang wrote:
         | Ok, we'll add that bit to the title above. Thanks!
        
       | nsonha wrote:
       | It would be nice but the problem is not that big of a deal if you
       | use any of the community libraries they mentioned.
        
       | rcme wrote:
       | There are good typed deserialization libraries. Personally, I
       | prefer runtypes but there are options.
        
         | decs wrote:
         | Agree, zod, arktype, and typia are impressively easy to use!
         | Though, I feel that this environment created a different
         | problem of spreading developers into multiple solutions. So for
         | lib devs like me, we end up having to choose between coupling
         | with a single validation lib or managing support for multiple
         | (like tRPC does). To address that, I ended up doing a reusable
         | lightweight lib that wraps that logic for supporting multiple:
         | https://typeschema.com
        
           | code_biologist wrote:
           | Thanks for the lib! I'm always charmed to come across such a
           | concrete example of the fundamental theorem of software
           | engineering: "We can solve any problem by introducing an
           | extra level of indirection."
        
       | andix wrote:
       | There is a good reason for not doing this. Typescript would
       | become some kind of runtime on top of JavaScript. A new language
       | that compiles to JavaScript. Currently TS is only JavaScript with
       | type annotations.
       | 
       | There are many languages that compile to JavaScript. Pick one of
       | them and use it!
       | 
       | And I have the feeling, that people who want runtime typed
       | Typescript would rather like to write Java/OOP style code instead
       | of JavaScript. But JavaScript is a dynamically typed language,
       | and that's also nice. Be happy with what you have!
        
         | shortrounddev2 wrote:
         | The reason we want typescript to have java-like features is
         | because we work on teams which have decided, outside of our
         | control, that we are going to write our backend in JS/TS simply
         | because it's easier for the bootcamp grads to transition to
         | backend since they already know JS on the frontend. If we wrote
         | our backend in Java, it would require the bootcamp grads to
         | learn a new language, which they're not prepared to do.
         | Choosing typescript or javascript on the backend is not about
         | choosing the right tool for the job (because they are
         | objectively not the right tool for backend development). It is
         | mostly about minimizing the cost of our labor sourcing
         | 
         | As such, RTTI would make typescript go from a compromise
         | language (we use it because we are stuck in the JS ecosystem,
         | not because it's a good tool) to a legitimately useful backend
         | language (We use it because it has the right features for the
         | use-case)
         | 
         | If I could choose what language we use on the backend, I would
         | leave the JS ecosystem entirely and write everything in .Net.
         | But it's difficult to find .Net developers since every bootcamp
         | these days produces react developers
        
           | andix wrote:
           | So you want TypeScript to be Java, but you don't want to use
           | Java, because your developers only know TypeScipt. Sounds
           | like an unsolvable problem.
        
             | shortrounddev2 wrote:
             | The solution is to pile features onto typescript that were
             | never intended to be there, the same way we have done with
             | Javascript, HTML, CSS, and HTTP. None of these things are
             | pure, and all of them have been ravaged by competing
             | interests and committees who were all making financially
             | driven decisions when writing the standards.
             | 
             | It would be best to abandon javascript and typescript as
             | backend languages. I don't mind them on the frontend
             | because a typescript compiler is useful when the
             | application you're writing is _originating_ data and not
             | _receiving_ it. And javascript does DOM manipulation
             | admirably. However, we live in a world where humans are
             | more expensive than computers. If I had my way, we 'd write
             | C# backends and Angular/Typescript frontends, but that's
             | not the world we live in. Everything has to be JS because
             | most people employed as "software engineers" are not truly
             | very good at their jobs
        
               | kristiandupont wrote:
               | I, on the other hand, would pick TS over .NET or Java any
               | day. But I am sure you will conclude that it can only be
               | because I am no good at my job.
        
               | shortrounddev2 wrote:
               | No, I'm sure you have your reasons, but deserializing and
               | validating is much more painful in typescript than it is
               | in .Net or Java so I'm not sure why you would choose that
        
         | twelve40 wrote:
         | > dynamically typed language, and that's also nice
         | 
         | what is nice about a dynamically typed language? like,
         | seriously, can you list some reasons for a dynamically typed
         | language to exist?
        
           | andix wrote:
           | Types can get complicated. To an extent that code gets
           | extremely overcomplicated by using a typed language. Typed
           | languages encourage to use many layers of DTOs and models.
           | 
           | With dynamic languages you can just code, without being held
           | back by a OOP type system, but it can get very complicated to
           | understand what the typed of you parameters and return values
           | actually are.
           | 
           | Typescript gives you the best of both worlds.
        
           | Barrin92 wrote:
           | Peter Norvig summed it up in one of his presentations
           | https://norvig.com/design-patterns/design-patterns.pdf
           | 
           |  _" Dynamic Languages have fewer language limitations Less
           | need for bookkeeping objects and classes Less need to get
           | around class-restricted design. Study of the Design Patterns
           | book: 16 of 23 patterns have qualitatively simpler
           | implementation in Lisp or Dylan than in C++ for at least some
           | uses of each pattern[...]"_
        
         | fzeindl wrote:
         | You can use Kotlin and compile to JavaScript. It's type system
         | is better and the standard library greater _scnr_
        
           | andix wrote:
           | Exactly. Pick whatever language you like. There are many more
           | options.
        
           | booi wrote:
           | This is the way. Best of both worlds although using js
           | libraries is kind of a pain
        
           | lf-non wrote:
           | Kotlin's type system works great for interop with a nominally
           | typed lang like java but for interop with a dynamically typed
           | lang like js and myriad of its libs not designed with type
           | safety in mind, structural typing is far more convenient.
        
         | adjav wrote:
         | My understanding has long been that web developers have decided
         | to turn Javascript into C#, one proposal at a time.
        
         | asherah wrote:
         | typescript enums exist and are compiled to javascript (other
         | than const enums)
        
           | lolinder wrote:
           | That TypeScript fails to live up perfectly to its design
           | goals doesn't mean it should adopt additional anti-features.
        
           | andix wrote:
           | And that's one of the features of typescript that really
           | sucks. String union types work so much better.
        
             | moystard wrote:
             | Why does typescript enum really suck?
        
               | Waterluvian wrote:
               | There's a _ton_ written about this if you search for
               | "typescript enums."
               | 
               | I just finished removing them from a major project.
               | Here's a few of my personal notes:
               | 
               | 1. They don't play well with duck typing. (Eg. show me a
               | subset of an enum)
               | 
               | 2. They require an import every time you want to utilize
               | them.
               | 
               | 3. They are pretty wordy compared to union strings.
               | 
               | 4. Their string value version encourages misuse as a key-
               | value pair.
               | 
               | 5. Unless you use the string value version, they suck to
               | debug because logs just show 0,1,2,3.
        
               | WorldMaker wrote:
               | Another one: they conflate Type and (Locator) Instance in
               | a unique way that just about nothing else in TS does.
               | Those are two very different things with the same name
               | with Typescript's (antiquated) enums.
               | 
               | There are too many ways to accidentally
               | import/redeclare/rescope the Type of an enum so that TS
               | "knows" the Type, but because that type (generally) has
               | the same "name" as the most likely (Locator) Instance it
               | assumes the same access applies leaving runtime errors
               | behind when that Instance isn't actually
               | imported/available. Typescript has no easy way to tell
               | the difference between access to the Type isn't access to
               | the (Locator) Instance (nor vice versa). Reasoning about
               | those runtime errors or preventing them is additionally
               | tough for people _too_ because of the same  "name"
               | problem for two different things.
               | 
               | This is something that's painfully hard to avoid in cases
               | where you are trying to encapsulate an API's Types
               | separate from its imports/exports because they might be
               | introduced or manipulated at runtime (plugins, sandboxes,
               | proxies, etc). Unfortunately, this is also too easy to
               | accidentally do even when you aren't intentionally doing
               | something complicated like that (trying to generate
               | automated .d.ts files in a bundling toolchain, for
               | example, when APIs are in the boundary space between
               | unintentional public API and internal tree-shaking or
               | optimized symbol renaming).
        
               | andix wrote:
               | Thanks for putting into words why they just "feel" so
               | wrong.
        
               | graypegg wrote:
               | Typescript enums emit a really weird object at runtime
               | 
               | enum CheckboxState { On; ParentOn; Off; }
               | 
               | Becomes
               | 
               | { [0]: "On", "On": 0, [1]: "ParentOn", "ParentOn": 1,
               | [2]: "Off", "Off": 2 }
               | 
               | So things like Object.keys give bizarre results. It's
               | done this way so you can use the name or the value as an
               | index.
        
               | eyelidlessness wrote:
               | To be clear, this kind of structure is only emitted for
               | numeric enums. String enums with explicitly declared
               | static values are roughly equivalent to the equivalent
               | Record<string, string> (runtime) and a corresponding type
               | T[keyof T] (type check time).
               | 
               | IME, most of the complaints about enums apply only to
               | numeric ones.
               | 
               | The major exception to that AFAIK is the fact that enum
               | members of any type are treated as nominally typed (as in
               | A.Foo is not assignable to B.Foo even if they resolve to
               | the same static value). I am among the minority who
               | consider this a good thing, but I recognize that it
               | violates expectations and so I understand why my position
               | isn't widely shared.
        
               | andix wrote:
               | Let's turn it around, union types are so much easier to
               | use and so much more powerful. Enums have only a small
               | subset of the features, are not compatible to JavaScript
               | code and are hard to understand (read the docs about type
               | script enums and you will see).
        
         | joshmarinacci wrote:
         | Dynamically typed means I can look up the type of an object at
         | runtime. JavaScript lets us do this with classes/prototypes.
         | Since TypeScript adds types and enums and interfaces, why can't
         | it let us look up those at runtime too? It would seem to fit
         | with the way JS works.
        
         | Arainach wrote:
         | For any sufficiently large project, dynamically typed languages
         | are not nice, they are a series of interweaved disasters
         | consisting of constantly tripping over what you thought was
         | your feet but is actually NaN and trying to fall forward rather
         | than collapsing entirely.
         | 
         | In every workflow I've seen, TypeScript is already a language
         | that gets compiled to JS. It might as well take full advantage.
        
           | andix wrote:
           | Typescript is not really compiled to JS, only the type
           | annotations are removed.
           | 
           | To make dynamically typed languages nice for bigger projects
           | we have typescript for type annotations (it's does not make
           | it a statically typed language!). It is there, it is used, it
           | scales and it works. If your type script project "collapses
           | entirely", it's probably not the languages fault.
        
         | vbezhenar wrote:
         | TypeScript is not JavaScript with type annotations. One of the
         | modes, may be. TypeScript supports emitting old JS
         | constructions which look nothing like original typescript code.
         | So it's more like type annotations + babel. Adding one more
         | thing to this set. Extremely useful thing. I think it's a good
         | idea. I miss it. It's crazy that I can't JSON.parse string into
         | typed structure safely. Every other language can do that.
        
           | andix wrote:
           | No, this is not crazy, this is the design goal of TypeScript.
           | 
           | If you want a statically and runtime typed language in the
           | browser, you should not use typescript. Use Kotlin, Rescript,
           | ...
        
           | mrloba wrote:
           | You can easily parse json into types using something like
           | typebox. Not only does this work, it works much better than
           | many other languages. Have fun trying to represent even a
           | simple patch request, or discriminated union, in something
           | like c#
        
         | whalesalad wrote:
         | You can have both. This is the beauty of lisp -
         | https://en.wikipedia.org/wiki/Homoiconicity
         | 
         | But in all seriousness you can gain reflection without a
         | runtime. Just expose the types as data.
         | 
         | Seems foolish to _not_ do something like this. Particularly
         | when you look at the lengths so many devs have gone to try and
         | replicate it.
        
         | armchairhacker wrote:
         | Not necessarily.
         | 
         | Consider                   const fooType =
         | generateTypeInfo!<Foo>();
         | 
         | Where `generateTypeInfo!` is a macro that expands to a JS
         | object encoding the "Foo" type (e.g. if `Foo` a record type,
         | `fooType` will be a record with its encoded field types). It
         | still compiles to readable JavaScript.
         | 
         | What this macro _does_ break is that TS = JavaScript with type
         | annotations, and all you need to do to compile is remove those
         | annotations (excluding enums, but they are all-but-deprecated
         | and obsoleted by string unions) without even type-checking.
         | Since now you also need to expand the `generateTypeInfo!`,
         | which requires actually computing the structural type of `Foo`
         | (and if you want any sort of nominal type metadata, that too).
         | 
         | And that's still a problem because type-checking is slow, but
         | removing the annotations is fast. If there's a limited way to
         | resolve types for these annotations which restricts the
         | resolution scope, that would be a good candidate.
         | 
         | ---
         | 
         | There's also more issues with TypeScript having a separate
         | runtime besides it not being JavaScript. TypeScript types are
         | structural, so they currently _are_ available at runtime: to
         | determine an object's type, inspect its structure. Anything
         | more and you quickly run into non-trivial cases being literally
         | impossible: if you want erased nominal information like whether
         | a string is part of a string union, TypeScript's type system is
         | Turing complete; and if you want the nominal type name,
         | implicit structural conversions mean that once a value leaves
         | its annotated cast or definition it's effectively undefined.
        
           | baxuz wrote:
           | I'm not sure what `generateTypeInfo!<Foo>();` is supposed to
           | be, but as far as I'm aware there is no way to execute
           | anything in a JS engine from a type generic.
        
             | __jem wrote:
             | It's meant to represent a hypothetical TS compiler builtin
             | that does codegen for you.
        
               | baxuz wrote:
               | Ah, yeah I get it.
        
           | scotty79 wrote:
           | What if this macro could be expanded into valid typescript by
           | preprocessor that runs before typescript compiler?
        
             | armchairhacker wrote:
             | That's an option, and maybe even the ideal one: an
             | extension which takes a TypeScript+macros file and converts
             | it into TypeScript before feeding to the TypeScript
             | compiler.
             | 
             | However, such a preprocessor will basically need to re-
             | implement TypeScript's type checking. So either TypeScript
             | must expose it via an API, or the preprocessor needs to
             | itself implement a subset (which as mentioned, could also
             | be faster)
        
               | matt_kantor wrote:
               | This already exists. One example posted elsewhere in
               | these comments is tst-reflect[1], with which you can
               | write this:                   const fooType =
               | getType<Foo>();
               | 
               | Which is exactly what you wanted, just as a plugin to
               | TypeScript rather than built into the official compiler.
               | 
               | [1]: https://www.npmjs.com/package/tst-reflect
        
         | random_mutex wrote:
         | ReasonML
        
           | dimitrios1 wrote:
           | ReasonML suffered tremendously when the community split and
           | went off to do ReScript. I don't think either have recovered
           | the original luster.
        
           | [deleted]
        
         | paxys wrote:
         | > Typescript would become some kind of runtime on top of
         | JavaScript. A new language that compiles to JavaScript.
         | 
         | Typescript isn't a runtime on top of JavaScript, but it very
         | much is "a new language that compiles to JavaScript".
        
           | codeflo wrote:
           | Yes, but it's special in that it compiles by erasure. (Mostly
           | -- the cases where it doesn't are considered historical
           | mistakes.)
        
             | vanviegen wrote:
             | Ok. And why is that important? So one could meticulously
             | add typing to your JavaScript application, and then strip
             | it all out with a regex in order to deploy? What real-life
             | benefit does 'compile by erasure' offer?
        
               | codeflo wrote:
               | That's essentially what all the fast transpilers do --
               | esbuild, babel etc. They don't typecheck the code at all,
               | they just parse it and strip out the type annotations.
               | 
               | This means that you can run and test code that doesn't
               | typecheck yet -- very useful during development. Also,
               | production builds can run the typechecker in parallel
               | with other build steps. That's how we optimized our build
               | system at work.
               | 
               | But essentially, it's a design choice by the TypeScript
               | team. They've decided that TypeScript shouldn't add
               | runtime features on top of JavaScript, but instead should
               | simply _type_ JavaScript, and I think this has
               | contributed to the success of TypeScript.
        
               | johnfn wrote:
               | I think the point is that TypeScript isn't really "a new
               | language". It's an existing language with an additional
               | feature. The fact that TS maintains the promise that
               | types can be stripped means that TS is upholding a
               | contract that it will not stray from Javascript. It
               | can't, for example, add new language features.
        
         | a_wild_dandan wrote:
         | I'm misunderstanding your reasoning here. TS is _already_ a new
         | (superset) language which compiles to JS. Runtime types solve
         | the problem of maintaining two duplicate, separate type systems
         | -- one for compilation, one for validating data. I 'm not
         | seeing how that's related to OOP. For instance, my preferred
         | workaround lib for this problem, `io-ts`, leans hard on
         | functional programming.
        
           | PaulHoule wrote:
           | Yeah but just because types exist at compile time doesn't
           | mean they exist at run time.
           | 
           | For instance with Generics in Java a List<String> is the same
           | as a List<Integer> at run time, the compiler can enforce
           | rules that let you add a String to one but not add a String
           | to the other but the runtime has no idea. This has various
           | negative consequences but it also let them retrofit generic
           | collections on top of the old collection implementation in
           | Java unlike the disaster in .NET where both had to coexist
           | for years.
           | 
           | Similarly C compiles to machine code and in machine code
           | there are just memory locations and registers, types are
           | implicit in how you use those things but not spelled out
           | explicitly. C++ does have RTTI but is one of the many open
           | pits, like Exceptions, in C++.
           | 
           | Typescript types are the same way, once the compiler has done
           | its type checking you know the code is going to behave
           | according to the type system even if the types have been
           | "erased".
        
             | einrealist wrote:
             | Java's generic type information (aka parameterized types)
             | is available at runtime through reflection.
        
               | PaulHoule wrote:
               | Depends on the situation. If you just make an
               | ArrayList<X> (for some specific class X) you can call
               | getClass() on that object and see it is an ArrayList but
               | you cannot find out about the X.
               | 
               | If you make an ArrayListX that is not generic but extends
               | ArrayList<X> it is possible to see the type parameter
               | that was extended, the same is true for implementations.
               | 
               | There are other kinds of type unerasure that you can use
               | w/o the language supporting it explictly, such as you
               | could pass the type parameter X.class into the
               | constructor and put it in a field so that you could call
               | some method like getContainedClass() and get a copy of X.
               | 
               | Now the introspection/reflection API does have support
               | for talking about parameterized generic types that
               | doesn't mean that information always exists at runtime.
               | 
               | I worked on a crazy project where I did a lot of fighting
               | with ordinary types and parameterized types and unerasing
               | types by rewriting the names of methods to avoid
               | conflicts, if you have methods like                  A
               | doSomethingTo(B)        A doSomethingTo(C)
               | 
               | you can rewrite these to                  Expression<A>
               | doSomethingToB(Expression<B>)        Expression<A>
               | doSomethingToC(Expression<C>)
               | 
               | but you can't have an overload that takes two differently
               | parameterized expressions, this lets you write Java code
               | in a lisp-like syntax that can be metaprogrammed on:
               | 
               | https://github.com/paulhoule/ferocity/blob/main/ferocity-
               | std...
               | 
               | that project got me thinking a lot about the various ways
               | types manifest in Java and I made the discovery that when
               | you add Expression types you practically discover an
               | extended type systems where there are many things that
               | are implied by the existence of ordinary Java types.
        
               | einrealist wrote:
               | I know how it works. The point of the topic was to have
               | type information available, so we can use it for things
               | like dynamic binding. No one asks for the runtime to be
               | as strict as the type system (the compiler).
               | 
               | I like Venkat's presentations:
               | https://www.youtube.com/watch?v=34oiEq9nD0M
               | 
               | BTW. I do not agree with the opinion in the topic. Since
               | Typescript is compiled to something else (usually JS),
               | I'd prefer Typescript to have proper annotations (there
               | are "decorators") and compiler hooks and just use code
               | generation for concerns like (de)serialization.
        
           | Quekid5 wrote:
           | > TS is already a new (superset) language which compiles to
           | JS.
           | 
           | Yes, but also no. The point is that it doesn't really add
           | more _semantics_ over plain JS. You can erase all the type
           | annotations (well, replace with  "any") and it'll do the same
           | thing if you ignore the type checking.
           | 
           | If there's any "transformation" from TS to different-looking
           | JS[0], it's mostly just syntactic embellishment (think LISP
           | macros and such), not semantic.
           | 
           | [0] Not sure if there is, tbh
        
           | lolinder wrote:
           | Emitting types would run counter to several of TypeScript's
           | Design Goals [0]. In particular, it would violate:
           | 
           | > 3. Impose no runtime overhead on emitted programs.
           | 
           | > 9. Use a consistent, fully erasable, structural type
           | system.
           | 
           | It's also explicitly called out as a non-goal in that doc:
           | 
           | > 5. Add or rely on run-time type information in programs, or
           | emit different code based on the results of the type system.
           | Instead, encourage programming patterns that do not require
           | run-time metadata.
           | 
           | > 6. Provide additional runtime functionality or libraries.
           | Instead, use TypeScript to describe existing libraries.
           | 
           | [0] https://github.com/Microsoft/TypeScript/wiki/TypeScript-
           | Desi...
        
             | wvenable wrote:
             | Emitting type information to some kind of separate common
             | format wouldn't undermine most of these goals. There are
             | already apparently dozens of tools that people can use for
             | this task in a dozen different ways. Just have TS emit the
             | data.
             | 
             | In this way there is no runtime overhead (point #3) -- it's
             | pure data to be optionally consumed. They wouldn't have to
             | prescribe any particular reflection module (point #6).
             | 
             | The only point this would violate is #5 but that is, of
             | course, the point. We want them to reconsider because it's
             | such a powerfully useful feature. And people are doing it
             | on top of and outside of TypeScript where TypeScript would
             | be best tool to give this information for TS users.
        
               | lolinder wrote:
               | It would violate #9 no matter what implementation you
               | use, and #9 is absolutely essential to tools like
               | ESBuild, Deno, and Bun, which all rely on the assumption
               | that they can nearly instantly strip out the type
               | annotations and execute the code as JS.
        
               | wvenable wrote:
               | You'd still be able to execute the code as JS. Your
               | library that uses type reflection wouldn't work anymore
               | but that's true of all these solutions.
        
               | lolinder wrote:
               | No, it's not. I can take a library that uses zod, strip
               | the annotations, and it will execute perfectly anywhere I
               | want to run it.
        
               | wvenable wrote:
               | That's because Zod doesn't use type annotations as input.
               | We're talking about wanting to use type annotations as
               | input so that we don't have to make our code as ugly as
               | Zod makes it.
        
               | RyanCavanaugh wrote:
               | TypeScript dev lead here.
               | 
               | Today, you can already write a program using the
               | TypeScript API to inspect all of this information to
               | accomplish whichever scenario is at hand. The existence
               | of all these tools, each with different opinions on
               | design direction and implementation trade-offs,
               | demonstrate that this is possible. Yet it's not
               | demonstrated how those tools would benefit from reading
               | from a data file as opposed to using the TypeScript API.
               | 
               | Something like api-extractor has different constraints
               | from io-ts which has different constraints from
               | typescript-schema. The API exists today and is apparently
               | sufficient to meet all these tools' needs, yet what's
               | proposed is a data file that can encapsulate any possible
               | operation you might perform with that API.
               | 
               | Having TypeScript try to imagine, implement, and maintain
               | a data file format that can satisfy _all_ of these tools'
               | use cases, plus any future tool's use case, is a
               | tremendous effort with no clear upside over using the
               | existing API.
               | 
               | It's easy to gain support for the idea of "put the types
               | in a file" because anyone reading that can imagine a
               | straightforward implementation that just achieves their
               | particular goals, but everyone's goals are different and
               | the amount of overlap is not actually all that high when
               | you look at the wide breadth of tools in the list.
               | There's a very different amount of information you'd need
               | to enable a type-aware linter (which is basically type
               | info on every expression in the program!), as compared to
               | a simple documentation generator (which might only need
               | top-level declaration info).
        
               | wvenable wrote:
               | Hard to argue with that! I wonder why this isn't
               | considered a solution to the author of this site.
        
               | lolinder wrote:
               | The author explicitly calls out the existence of all of
               | these tools as _being_ the problem. They seem to want a
               | canonical version that TypeScript itself officially
               | supports.
        
               | RyanCavanaugh wrote:
               | Situation: There are 14 competing type representation
               | formats
               | 
               | TypeScript: We can write our own type file format!
               | 
               | Situation: There are 15 competing type representation
               | formats
        
               | Dylan16807 wrote:
               | If typescript itself defines a format, it's hard to
               | imagine that the majority of people won't switch to it.
               | 
               | Though while there's a lot of type-data tools, are there
               | actually a lot of type-data _formats_ out there right
               | now? I 've been using zod, and it doesn't have one. You
               | have to use code to tell it about a type. Someone did
               | make a library to let zod load types from pure data, but
               | the format used there is... typescript source code.
        
             | vbezhenar wrote:
             | If some design goals are stupid they must be changed. It's
             | not god word. It's human word. And this human was wrong.
        
               | lolinder wrote:
               | This isn't just some of the design goals, type erasure is
               | the fundamental guiding principle of TypeScript that
               | allowed it to become successful. Throwing it away because
               | it complicates certain programming patterns should not be
               | done lightly.
        
               | andix wrote:
               | In my opinion they are not stupid, they make a lot of
               | sense. And many people seem to agree and use typescript.
               | If you don't agree, use something else. There are many
               | alternatives, pick something that is ,,smart" in your
               | opinion.
        
               | chucklenorris wrote:
               | Unfortunately i can't. Like most of the people here i
               | work in a company, with other people and i can't chose
               | $language that is less dumb for obvious reasons.
               | Typescript IS the only practical solution for web
               | development at scale. I'm stuck with the design
               | philosophy of a guy that's not facing my problems and
               | obviously doesn't care.
        
           | epolanski wrote:
           | Small ot, if you like io-ts, @effect/schema is the spiritual
           | successor from the same ecosystem.
           | 
           | The fp-ts, io-ts author Giulio Canti has decided that the
           | best way to proceed was to merge the two communities of fp-ts
           | and effect, even though it's his work that is mostly known
           | with effect being much more niche.
           | 
           | It's essentially io-ts squared in its powers. The amount of
           | things you get from schemas are endless, not just decoders
           | and encoders but also apis, lenses, constructors, and many
           | other things.
           | 
           | It's obviously heavily fp-leaning, albeit I would say effect
           | systems such as effect, based on Scala's ZIO, are much more
           | approachable than haskell/purescript-like languages.
        
       | benatkin wrote:
       | Please give me an integer type.
       | 
       | Just kidding, but I'm not pushing for JavaScript anymore. If
       | rust/WASM works as well, I say go with that.
        
         | hajile wrote:
         | JS added BigInts quite a while ago.
        
           | [deleted]
        
           | vbezhenar wrote:
           | Yet JSON.parse("9007199254740993") returns 9007199254740992,
           | not 9007199254740993n.
        
         | orthecreedence wrote:
         | > Just kidding, but I'm not pushing for JavaScript anymore. If
         | rust/WASM works as well, I say go with that.
         | 
         | This is the direction I'm going. I use rust a LOT these days,
         | and after trying out typescript for a few projects over the
         | course of a few months, I absolutely hate it when comparing it
         | to rust or even any other compiled language. Something about it
         | just rubs me the wrong way...maybe the fact that it has to be
         | JS-compatible, so the type system seems really crude? I can't
         | put my finger on it. It sort of hits this weird inbetween where
         | js is quick to write/prototype and rust is extremely "correct"
         | but the ts type system slows things down/annoys me without
         | providing enough benefits. Also, working with it in nested
         | projects via npm tends to be a huge pain in the ass. Maybe I
         | need to switch to Deno or something so it's native?
         | 
         | Now that rust/wasm is ramping up, I'm considering using rust
         | for the API layer and something like Leptos for the frontend.
         | I've been getting into svelte a lot, and Leptos seems similar
         | enough to not be a huge leap.
        
           | benatkin wrote:
           | I'm curious what you think about Dart/Flutter if you've
           | gotten a chance to dig into them. I am very impressed, but it
           | trades simplicity for being cross platform. It has a nice set
           | of types though. https://dart.dev/language/built-in-types
           | 
           | It also has a WASM compilation target that is under early
           | development. https://docs.flutter.dev/platform-
           | integration/web/wasm
        
             | orthecreedence wrote:
             | Good question! I prototyped some stuff on Dart/Flutter.
             | What I took away from it is that a) I really liked Flutter
             | b) I really do not like Dart. I really tried to like Dart
             | (mainly because I was enthralled by the idea of Flutter)
             | but it just didn't click for me. It seemed like the syntax
             | was trying to be intuitive in some ways, logical in others,
             | and that incongruity really made it hard for me to pick up.
             | I think overall it felt inconsistent in confusing ways. I
             | also was both simulaneously impressed and disgusted by the
             | fact that it render everything in a canvas for desktop...I
             | mean, it totally makes sense, and what a great way to get
             | consistent rendering acros platforms, but I wonder what the
             | tradeoffs are. Accessibility must suffer in some way, but
             | maybe they figured all that out.
             | 
             | I wish Flutter was just a regular GUI library for another
             | language (C maybe, so you can use it from everywhere,
             | that'd be nice). Dart really killed it for me. Also, I know
             | it's beating a dead horse, but Google doesn't have a good
             | track record with long term support of their projects. If
             | it was a grassroots open source project, I'd probably feel
             | a lot more secure putting aside my Dart-inflicted OCD and
             | really picking it up.
             | 
             | Given my current love affair with Rust, my main squeeze
             | right now is Tauri. Once they hit mobile platforms I think
             | it'll be unstoppable, and in the meantime whatever you can
             | do in Tauri you could probably translate to Ionic.
        
       | dvt wrote:
       | I dunno, this seems like it would be out of scope for something
       | like TS proper (there's already been a ton of feature creep,
       | anyway). Reflection is generally implemented via runtimes, which
       | can be very clunky. Is it really worth doing this in JS? Tooling
       | already seems too bulky as is.
        
       | kazinator wrote:
       | Fairly recently I built a C library for object serialization,
       | based on run-time reflection. Run-time reflection is not
       | necessary to the task and makes it perform worse than a code-
       | generating solution.
       | 
       | The run-time reflection approach is good in one way: it doesn't
       | add tooling to the project. All the modules that use
       | serialization have to make a bunch of tedious API calls to build
       | the type object which represents the C structure. This is created
       | once and stashed in a global variable. Then it is used as a
       | parameter when serializing and deserializing.
       | 
       | There is a performance impact because the marshaling code is
       | interpreting the type object; it recursively walks the type
       | object, and in parallel it walks the C object to extract or stuff
       | material.
       | 
       | A generative approach would just write a serialization and
       | deserialization stub. There would be no need for any type object
       | to be walked at run-time. No need to construct such objects at
       | startup and no need to carry the library for that.
       | 
       | But there would be some tool which itself has to be compiled (for
       | the build machine, not the embedded targets), and then some
       | Makefile steps to run that tool on some interface files. The
       | thought of inflicting that one the project made me go yuck.
       | 
       | A third possibility is to have the run-time type info objects,
       | and add JIT. Why do something easy, like a code generation tool
       | called out of Makefile, when you can do something hard and
       | nonportable?
        
       | Waterluvian wrote:
       | Above all of what I write below, I think that this is a very
       | valid issue for discussion and debate. I don't think there's one
       | objective correct answer. So this isn't me dictating what
       | TypeScript shalt be.
       | 
       | TypeScript is an entirely optional layer on top of JavaScript,
       | with the exception of `Enum` that emits an object, many of which
       | see as a mistake. You don't even have to "transform" TS code to
       | get JS: you just have to delete the typings. The rest is just JS.
       | 
       | Unless you want to depart heavily from this principle, which I
       | think is crucially important so long as there's still human-
       | maintained JS code out there, what I think they're asking for is
       | a library to take the types and write serializers/validators for.
       | Which there are many of. So I think the real request is to make
       | the one canonical choice out of a field of many choices, which I
       | also agree with the spirit of. But is that really in scope for
       | the TypeScript project?
       | 
       | What I personally don't want is runtime reflection for
       | TypeScript. Or at least, not a core part of the language. Because
       | I like that TypeScript is just for compilation and at runtime you
       | just have JavaScript, without any sort of abstraction layer that
       | turns JS into some sort of intermediate representation with
       | overhead or more indirection for debugging. I _cherish_ the fact
       | that even without source mappings, my output JS is perfectly
       | legible and debuggable.
        
         | syspec wrote:
         | > You don't even have to "transform" TS code to get JS
         | 
         | Sure if you consider the whole language, typings
        
         | eyelidlessness wrote:
         | > with the exception of `Enum` that emits an object, many of
         | which see as a mistake
         | 
         | There are other exceptions, most of which are considered
         | mistakes as well, the most obvious which come to mind being
         | `module` and `namespace` as runtime constructs. But I'm fairly
         | sure these have been primarily used by TypeScript itself for at
         | least a few years, and even they recently migrated away.
         | 
         | Another one that comes to mind is, I believe, actually pretty
         | popular: what they refer to as "parameter properties", ie class
         | members whose types are defined in a constructor's parameters.
         | These seem to have escaped controversy because they eliminate a
         | lot of redundant boilerplate, and generally behave in obvious
         | ways (at least as obvious as their redundant boilerplate JS
         | equivalents).
        
       | zoogeny wrote:
       | This is the perennial problem with language design. Everyone
       | wants something and they even have reasonable grounds to ask for
       | it.
       | 
       | I myself have come across moments where some rtti/reflection
       | would have been useful. In those cases I was often able to use
       | branded types. Having something like that built into the language
       | might be nice. But I'd also support TypeScript and JavaScript
       | developers making the choice not to support it ever. IME, working
       | around rtti type code often forces the programmer to come up with
       | a much better approach.
        
       | JohnDotAwesome wrote:
       | Instead of pleading to the TypeScript gods, why not make a deal
       | with the JavaScript deities? Let's get type-checking into JS!
       | 
       | If I want runtime types, I reach for type guards. If I need to do
       | this a lot, then I reach for io-ts or zod and pretty much
       | exclusively write types as validators/codecs/schemas or what-
       | have-you.
       | 
       | I don't think TS - as a specification, type-checker, community,
       | or otherwise - needs to concern itself with runtime validation
       | UNLESS JS gets some agreed upon way to do it.
        
         | epolanski wrote:
         | I have huge doubts whether I'd like JS to have it really.
         | 
         | I feel like Promises, decorators and the new pipe operator all
         | went into the wrong directions with their implementations.
        
           | esprehn wrote:
           | How do you feel like promises went in the wrong direction?
           | 
           | (I'd also add modules to your list fwiw, they were designed
           | without taking performance into account.)
        
         | steve_adams_86 wrote:
         | I know it's not perfect, but I'm pretty content writing schemas
         | and types as validators with zod and deriving my types from
         | those. That you can derive the types easily and the validation
         | then evolves with your typing is really nice.
         | 
         | I've worked with people who find it too complicated or they
         | feel like it should be baked into the language, but I'd argue
         | there are so many contentious design choices in these libraries
         | that it might actually be best to be an implementation choice,
         | selected based on a project and its specific needs.
         | 
         | Zod has been very good to me though. It's quite easy to get up
         | and running with, and its API has never gotten in my way when
         | scaling things out.
         | 
         | My one complaint is that certain patterns I love, such as
         | runtime validation with zod and deriving types from schemas,
         | doesn't necessarily always play well with something like
         | pattern matching in ts-pattern. The type definitions behind
         | these libraries are labyrinths, and cases where something seems
         | like it should work won't always behave as expected. On some
         | level, I do wish these were seamless language level features,
         | though I fully recognize these are selfish desires.
         | 
         | But imagine having runtime safety combined with exhaustive
         | pattern matching. I'd be very happy to have that.
        
       | frou_dh wrote:
       | I was perfectly satisfied with using https://zod.dev for some
       | runtime data validation, and found it really cool that I didn't
       | have to define some nominal type off to the side and could
       | instead just say what I meant inline using a fluent API.
        
         | epolanski wrote:
         | Nominal types have different use cases.
         | 
         | Simple one, distinguishing `2` number with `2` currency in your
         | domain.
        
           | lf-non wrote:
           | We can use branded types to simulate nominal typing
           | 
           | https://zod.dev/?id=brand
        
       | unilynx wrote:
       | What I really miss is a way to extract type information directly
       | from the compiler. Ie to have a 'macro' that takes a type as an
       | input and returns a readable text or a json structure describing
       | that type
       | 
       | It still wouldn't be runtime typing, the compiler would just
       | insert a constant wherever you use such a macro so I don't think
       | it would conflict with typescript's goals. But it would make it a
       | lot easier to build extra checks when deserializing data - or
       | just give richer debug information.
       | 
       | But it would probably be hard for eg esbuild to support such a
       | feature if tsc adds it. So I couldn't use it anyway :)
        
       | moomoo11 wrote:
       | Use zod
        
       | william-evans wrote:
       | As listed, Typebox is excellent for this use case - it correctly
       | implements the JSON schema spec and allows you to use it to write
       | OpenAPI specifications. At my company we use this to write type-
       | safe handlers & generate our API documentation!
        
       | cannabis_sam wrote:
       | This is just the desperation that comes with poor understanding.
       | The strength of a type system should ideally be that you could
       | confidently execute the underlying code even with full type
       | erasure, and while I realize that TS has already sacrificed this
       | to some extent, adding reflection/runtime "types" would just
       | further degrade the value of TS.
       | 
       | No thanks! If you want this, compile java to JS or something
       | equally hamfisted...
        
       | lf-non wrote:
       | Deepkit (listed in the article) is a fascinating project and
       | really deserves to be more popular.
       | 
       | It also demonstrates that what is being asked for is actually
       | practical.
       | 
       | https://deepkit.io/
        
       | paxys wrote:
       | I had to read their problem statement like 4 times to understand
       | what they are asking for. This is exactly why simple, concise
       | writing is essential, and their wall of text is...not it.
       | 
       | > I love you. You do amazing work. You are gods among mortals.
       | You have brought JavaScript from the darkness, and given it the
       | warm light of strong typing. Look upon us, the cowering meek
       | masses, and understand that we live in the muck and mire of a
       | world where we are doomed to endlessly crawl on our bellies
       | through the alleys of Github seeking the one true npm. We will
       | forever wonder in the dark, until we have a type reflection
       | model.
       | 
       | What even are they getting at?
       | 
       | As for their actual ask (runtime type safety), it is probably not
       | going to happen because the TypeScript project has drawn the line
       | at not being an alternate or additive runtime for JavaScript.
       | Their job is simply to compile down to JS code and exit the
       | picture. Whatever happens after that (in V8 or elsewhere) is your
       | own business.
       | 
       | > TypeScript Needs to Emit Runtime Type Information
       | 
       | This is not possible at all because TypeScript is a _compiler_.
       | They are really asking for a net new product which has very
       | little to do with the TypeScript that exists today.
        
         | [deleted]
        
         | tinideiznaimnou wrote:
         | [flagged]
        
           | RyanCavanaugh wrote:
           | I'm here and I have no idea what you're talking about with
           | ESM imports. Please log a bug.
        
             | tinideiznaimnou wrote:
             | >I'm here
             | 
             | Hello. :-)
             | 
             | >Please log a bug.
             | 
             | I'll check if the bug opened last year (as Node 16
             | tightened ESM resolution... start to remember?) is still
             | open.
             | 
             | But nevermind that.
             | 
             | What I really want to ask you, is about this introduction:
             | 
             | >I love you. You do amazing work. You are gods among
             | mortals. You have brought JavaScript from the darkness, and
             | given it the warm light of strong typing. Look upon us, the
             | cowering meek masses, and understand that we live in the
             | muck and mire of a world where we are doomed to endlessly
             | crawl on our bellies through the alleys of Github seeking
             | the one true npm. We will forever wander in the dark, until
             | we have a type reflection model.
             | 
             | (source: https://github.com/akutruff/typescript-needs-types
             | i.e. TFA, as of 2023-07-08T00:05:20Z)
             | 
             | Had you read this text before I just brought it to your
             | attention?
             | 
             | What were your immediate feelings regarding its tone?
             | 
             | Did you enjoy being addressed like that?
             | 
             | Or were you embarrassed?
             | 
             | Or did you just brush it off as a harmless, playful display
             | of "nerdiness"?
             | 
             | Or something else entirely?
             | 
             | What would it take to convince you that, if someone needs
             | to debase themselves to "endlessly crawling on their
             | bellies" to get your attention as a platform vendor -- or
             | veer towards the other extreme (as in the case of my rants)
             | -- your "solution" just might have become part of a bigger
             | problem?
        
               | seattle_spring wrote:
               | Michael O'Church? Is that you?
        
               | tinideiznaimnou wrote:
               | Lemme check
        
             | tinideiznaimnou wrote:
             | https://github.com/microsoft/TypeScript/issues/54163#issuec
             | o...
             | 
             | >Hundreds of Github comments have been rehashed on this
             | issue over and over again. Import paths are not modified
             | during compilation, and we're not going to modify them
             | during compilation, and it isn't because we haven't thought
             | about it before and just need to spend another hundred
             | comments arguing about it.
             | 
             | >The general tenor of discussion here is not great and I
             | don't think this is likely to lead to any further
             | productive discussion, so I'm just going to lock this.
             | 
             | I'm talking about this thing, apologies if I haven't
             | referred to it precisely enough haha. So is it still "no
             | idea", or is it actually "let's pretend we don't hear him,
             | maybe he'll go away" (because you're understandably fed up
             | with answering the same question many times)?
             | 
             | ---
             | 
             | Listen, how about I just tell you why I'm asking you all
             | those weird little questions. I still want to hear how you
             | feel about being called a "god among mortals" for writing
             | JavaScript for Microsoft, but I mean c'mon. You're a busy
             | man, you just wondered "what's the ploy here" for a sec and
             | decided it's safest not to bother answering them, right?
             | 
             | I understand that you, like any software engineer, like to
             | work on impactful and meaningful things, and consequently
             | take a measure of pride in your work; so could I, for a
             | certain project, had I not allowed myself to be pressured
             | into building it in TS - by people with no skin in the
             | game, only the current majority consensus on their side
             | ("all JS bad, but TS least bad").
             | 
             | Let's summarize the original post:
             | 
             | - Someone humiliates themselves, literally _begging_ to be
             | heard out.
             | 
             | - They bring forth a _huge_ list of things that, beyond
             | reasonable doubt, prove that their concern is valid.
             | 
             | - They are pointedly ignored, or rebuffed with some form of
             | "I don't know what you are talking about" or "seems like a
             | you problem".
             | 
             | Seeing this dynamic begin to play out in a _feature
             | request_ (out-of-left-field as the whole thing may be),
             | well, that struck a fucking nerve, let me tell you. This
             | has been my exact experience with TS (and no other
             | programming language), when trying to address matters
             | including, but not limited to:
             | 
             | - Whether to use TS at all (which I shouldn't have conceded
             | to in the first place.)
             | 
             | - Whether TS can be adopted gradually (in my case it took
             | multiple rewrites.)
             | 
             | - Whether I'm just imagining that I'm not gaining much by
             | using TS (I'm not.)
             | 
             | - Whether I'm just imagining that I'm experiencing
             | drawbacks from using TS (I did.)
             | 
             | - Whether TS is "just JS with types" (which is about as
             | true as C++ being "just C with classes".)
             | 
             | - Whether the help implicitly offered, conditional on me
             | using TS because "that's what everyone uses now", will ever
             | materialize (which it didn't.)
             | 
             | - Whether I was using TS of my own free will (which is only
             | true insofar as I rose to the challenge of accomodating
             | others' supposed "discomfort" with good ol' JS, at my own
             | expense.)
             | 
             | Every time I raised any of those questions, I was faced
             | with gaslighting. And yes, in the end I did fall as low as
             | _begging_ my teammates for their help - after all, didn 't
             | I just rewrite working JS into nearly-working TS _so that
             | it would be more accessible to others_?
             | 
             | Unrelated subsequent experiences taught me that the
             | (former) coworkers in question might have been just as lost
             | with TS, and even more lost with the JS ecosystem in
             | general (whereas I feel mostly at home with it, coming from
             | Python), but they were reluctant to take accountability and
             | hence admit vulnerability. (Guess adding type annotations
             | doesn't necessarily make code easier to comprehend or
             | maintain, whether you come from a real dynamic language or
             | a real static language, huh.) Well, whatever, that one's on
             | them. And now it's on me to speak out against such insanity
             | as enabled by your product.
             | 
             | When I see someone _publicly_ putting themselves through
             | the same situation (or  "pretending" to - what's the
             | difference when everyone is on so many layers of irony that
             | it's not even funny anymore?), and it's not Clojure or Rust
             | or Zig or Nim or Julia -- or JavaScript -- but fucking
             | _TypeScript_ once again; and it 's not even their coworkers
             | that they're addressing in this manner, ridiculous in its
             | _sheer desperation_ , but they're talking to the fucking
             | _upstream_ , then I'm not going to be a "good sport"; for
             | me, this rapidly turns from "some stupid thing someone
             | wrote on the Internet" into a matter of professional
             | conscience.
             | 
             | Why did OP have to communicate in this acutely self-
             | deprecatory manner? Is it perhaps because of a systemic
             | issue in how the TS project handles feedback? Having
             | personally experienced the exact same dynamic when
             | discussing TypeScript, it seems such toxic communication
             | has "trickled down" from upstream to us "cowering meek
             | masses", i.e. the developers of Web-based software, i.e.
             | the people who really should know better, because so much
             | of what we build is intended to be directly consumed by
             | other human beings.
             | 
             | For me, this is because TypeScript is not _honest_ open
             | source software. Say it for all to hear: am I wrong that
             | the direction of TypeScript 's development is determined by
             | Microsoft's interests first, and the interests of the
             | community a distant second? And is it not misleading and
             | abusive in the slightest to have people learn "Microsoft-
             | flavored JavaScript" instead of the real JavaScript that
             | their browsers can execute, and pretend it's optional when
             | practice shows it's anything but?
             | 
             | The stock phrase "incredibly privileged" makes me sick, but
             | in this case you, Ryan, may truly not believe how
             | privileged your position is in comparison to downstream
             | developers around the entire globe. You're not the end-of-
             | line code-monkey just trying to give the non-technicals
             | some buttons they could click; you and your team are
             | literally imposing your wills on a pre-existing community
             | of fellow programmers, leveraging the unlikely synergy of
             | Microsoft's marketing machine and the open source
             | community's network effects.
             | 
             | On Monday, you will keep moving TypeScript onward; freely
             | benefitting from the community's input on how to do what
             | you're already doing, only better - more efficiently, more
             | correctly. And just as freely ignoring the community's
             | input on whether you're doing the right thing in the first
             | place.
             | 
             | Meanwhile I'll still be recovering from the way your
             | technology ended up impacting my life, no exaggeration,
             | let's not even go there. If even 1% of TS users have been
             | through a similar wringer as myself, that makes for how
             | many people hobbled by your work? Calculate, and consider.
             | 
             | All the best.
        
         | jxf wrote:
         | > This is exactly why simple, concise writing is essential, and
         | their wall of text is...not it.
         | 
         | I only skimmed this but felt it was clear. They're asking for
         | TypeScript, as part of the type erasure, to emit the type
         | information it has discovered about the types in a side channel
         | to the emitted JavaScript. Think of, say, PDB files as an
         | analogy.
         | 
         | > They are really asking for a net new product which has very
         | little to do with the TypeScript that exists today.
         | 
         | This is information TypeScript already has today but which it
         | discards. It wouldn't take a "net new product".
        
           | [deleted]
        
           | RyanCavanaugh wrote:
           | You can use the TypeScript API to generate this information
           | at whichever level of detail you want.
           | 
           | The level of detail TS has about types during the checking
           | phase is much higher than you would want in practice for 99%
           | of projects (e.g. 1 + 2 + 3 has 6 different types associated
           | with it).
           | 
           | The level of detail TS has about types during the checking
           | phase is potentially lower than you would want in practice
           | for a lot of projects (which is critical since that makes the
           | whole feature useless if that happens). For example, the list
           | of properties of a particular generic instantiation is lazily
           | computed, but it's possible your program never pulls on the
           | list so it never exists in the first place, yet is something
           | your type-based tool might want to know.
        
             | jcparkyn wrote:
             | They're not asking for reflection on _all_ possible types
             | (which would have the problem you mentioned), just ones
             | explicitly requested at compile time via a function call.
        
         | [deleted]
        
         | spatialaustin wrote:
         | At the top of the README they link to "The 7 year old Github
         | issue" which describes the problem in they way you're asking
         | for.
         | 
         | https://github.com/microsoft/TypeScript/issues/3628
        
         | hn_throwaway_99 wrote:
         | > This is not possible at all because TypeScript is a compiler.
         | They are really asking for a net new product which has very
         | little to do with the TypeScript that exists today.
         | 
         | That's not correct. All you would really need to do is output
         | type information as JS objects and then support reflection
         | libraries that looked up information at runtime. Two examples
         | where this already happens:
         | 
         | 1. TS enums are output as JS objects, as opposed to, for
         | example, string literal union types. That is, "enum Foo { Bar =
         | 'BAR', Baz = 'BAZ }" outputs information that can be queried at
         | runtime, while "type Foo = 'BAR' | 'BAZ'" does not.
         | 
         | 2. TS already supports runtime type guards functions, https://w
         | ww.typescriptlang.org/docs/handbook/2/narrowing.htm.... It
         | wouldn't be hard to generate those functions automatically
         | using information already in the type system.
        
           | crooked-v wrote:
           | TypeScript enums only exist at all because they were included
           | early on before the project really narrowed on its current
           | goal of being "1-to-1 current JS, but with types". If
           | TypeScript were started from scratch right now with the
           | current philosophy, enums would never exist in the first
           | place.
        
             | tough wrote:
             | But I do like TS Enums, don't take them away
        
             | hn_throwaway_99 wrote:
             | Agreed, but two points:
             | 
             | 1. I was responding to the point that seemed to be arguing
             | that just because TS is a _compiler_ (to JS), that it
             | couldn 't support runtime type info. That's incorrect, and
             | different from the current philosophy of "TS should really
             | only use type _erasure_ when outputting JS code ".
             | 
             | 2. After many years I've come to the conclusion that there
             | is _huge_ benefit for an ecosystem to either (a) have a
             | "batteries included" mindset, or (b) have a way to "semi-
             | officially" designate associate libraries as being
             | supported. I think Java really excelled here. For example,
             | the Java Collections library was/is excellent, and for a
             | long time (not sure if it still is, I've been out of the
             | Java ecosystem for some time now) Apache Commons were the
             | go to place for libraries everyone used. Contrast that with
             | the Node/JS ecosystem, where basically "whatever gets the
             | most popular in NPM" becomes a semi-standard, but there are
             | still often 5 competing libraries, and until the module
             | owner decides to delete a widely used library or just stop
             | releasing updates - besides leftpad infamy, there was also
             | an issue where lodash basically went unreleased for a long
             | time despite needs for critical security patches.
             | 
             | When it comes to TS, I understand the guiding principle of
             | "we only implement type erasure", but I wish there at least
             | a way to e.g. set a tsconfig flag if you wanted to allow
             | runtime data, or to have the equivalent of Apache Commons
             | for TS.
        
         | flohofwoe wrote:
         | The Typescript compiler could probably emit additional JS files
         | with reflection info just as it currently emits .map and .d.ts
         | files (basically a 'type database' that exposes the information
         | that's already in the .d.ts file as JS module, and which can be
         | queried at runtime by type- and property-names (e.g. stuff like
         | "what was the original Typescript type for this Javascript
         | property").
         | 
         | The only missing link is then that Javascript objects don't
         | know their original Typescript type, that would need to be
         | magically injected by the TS compiler as a custom property.
         | 
         | How useful that would be in practice, no idea... I can pretty
         | much only see downsides (mainly increasing bloat).
         | 
         | Also the same thing can probably be implemented in 'user space'
         | by a tool which parses .d.ts files and code-generates such
         | type-database modules from that information.
        
         | jauntywundrkind wrote:
         | Counter to this post, as soon as I read the title I knew what
         | this was, & I knew it was speaking exactly to something we've
         | wanted for a long time. This is asking for more official &
         | better supported https://github.com/rbuckton/reflect-metadata .
         | 
         | TypeScript _is_ a compiler. It has a lot of type information
         | during compilation. We could write that type information out
         | into a file. Instead what we do is throw that information out
         | when the compile ends. Taking all that typing information  &
         | throwing it away at the end of compile time is a bad dumb &
         | silly limitation. Especially for a language like JavaScript,
         | which historically could be semi-proud it had such a strong
         | _Everything Is An Object_ philosophy running through it (such
         | as the malleable prototype-based inheritance system); so much
         | type information should be on that Class object. Reflect-
         | metadata for example defined new methods on Reflect to store
         | this metadata.
         | 
         | I could not be more delighted to see the pennon of this website
         | go up. We needed a rallying point for this. We needed a
         | rallying point for keeping class data around. A rallying point
         | for enriching the runtime with good actionable data is a good
         | rallying point.
         | 
         | It's not what's afoot here, but I think you're a bit off-base
         | about the impossibility of adding even _some_ type-safety. We
         | might not be able to get exact TS type safety. But we can
         | definitely build some safety in. Owing to the malleable
         | prototype-based type system in JS, we can add getters /setters
         | to objects to do a lot of type checking. This doesn't even
         | begin to explore the possibility of what we might do with
         | es2015's proxies, which could allow even more interesting
         | checks to be layered in. I also wish JS had an official AST
         | (and renderer), so had more official options for code-rewriting
         | that might let us weave in type checks.
         | 
         | What we can do as programmers is limited by what we have at our
         | disposal. Not throwing out all the typing information, keeping
         | it around at runtime, opens a lot of interesting doors.
        
           | yxre wrote:
           | Why not keep the package separate? I also thought of reflect-
           | metadata separately, and it doesn't hurt to allow users to
           | install plugins to augment core compiler behavior.
           | 
           | Some people have very tight constraints for payload size, and
           | types could blow up payloads
        
             | jauntywundrkind wrote:
             | It's hard for a plugin to always be begging for sufficient
             | hooks & access to read out the data. Maybe an external
             | project is fine, but it needs some real TLC, not just being
             | a side-quest by a maintainer or two.
             | 
             | Conceptually it feels like there should be/needs to be some
             | buy in on high, a shared vision that tsc is not the one,
             | only & singular tool in the typescript-verse that ever can
             | or will care about types. Trying to constantly break in &
             | exfiltrate the data isn't ever going to get a position
             | where the world takes this seriously; typescript needs
             | really should gladly be opening the gates.
             | 
             | As for whether the type information is in fact part of the
             | payload, that's a separate question, and one that should
             | ideally be configurable. It's definitely a bit of a complex
             | situation in general; ideally we'd have good/easy ways for
             | libraries to include this information but then we also want
             | want to be able to strip it out easily.
             | 
             | Maybe we just regenerate it as needed from ts source of
             | libraries when we need it. But that implies not running a
             | single typescript compile with one set of settings but
             | running many compiles, as each library has its own tsconfig
             | it'll need that informs how files are laid out & other
             | sundry details. I might be overcomplicating. Perhaps we
             | could just generate a foo.reflect.js, that has all the
             | reflection data? There's options.
        
         | johnfn wrote:
         | The first 7 words of the document are "TypeScript Needs to Emit
         | Runtime Type Information". Was that not clear? I guess I'm a
         | bit confused by your confusion, unless you don't know what
         | runtime type information is, in which case I suppose it's more
         | understandable - but in that case I suppose you're not really
         | the target audience.
        
         | cornstalks wrote:
         | > > _TypeScript Needs to Emit Runtime Type Information_
         | 
         | > _This is not possible at all because TypeScript is a_
         | compiler.
         | 
         | Sorry, can you clarify? Many compilers exist in other languages
         | that support RTTI, so it's not clear to me what you mean by
         | this.
        
           | paxys wrote:
           | There are plenty of projects that do the same for TypeScript
           | (e.g. https://github.com/typescript-rtti/typescript-rtti) and
           | plenty that support some kind of runtime reflection, and
           | overall emitting TS type information at compile time in some
           | readable format is a pretty trivial problem to solve. The
           | complicated part is on the other side - what do you do with
           | this information? How do you get JavaScript engines to
           | understand it?
        
             | wvenable wrote:
             | You don't get JavaScript engines to understand it. You use
             | a library.
        
               | paxys wrote:
               | So then...exactly how it is done today? TypeScript
               | provides an API to get type info at compile time.
               | Libraries write plugins to consume this type info and use
               | it for runtime and custom validation. What changes in
               | this new world?
        
               | code_biologist wrote:
               | > So then...exactly how it is done today? TypeScript
               | provides an API to get type info at compile time.
               | 
               | That's exactly it, it doesn't. That project you linked
               | (typescript-rtti) mentions in the README that you must
               | install and use it via ttypescript, a typescript wrapper
               | that patches the compilation process to expose
               | compilation details to plugins. Except that plugin API is
               | unofficial and changes break the ecosystem built on it.
               | For example, ttypescript doesn't work for TS 5 and the
               | dev doesn't want to spend time on it. ts-patch has
               | stepped in to provide a source transformer API for TS 5.
               | 
               | There's no way I can recommend libraries like typescript-
               | rtti in commercial projects until something changes. I
               | hope the ts-patch folks don't burn out.
        
         | goodpaul6 wrote:
         | > This is not possible at all because TypeScript is a compiler
         | 
         | Not sure if this supports your point. Lots of compilers emit
         | runtime type information, e.g. Golang, Java.
        
           | jakelazaroff wrote:
           | Those languages all have runtimes that can consume the type
           | information. TypeScript does not.
        
         | dclowd9901 wrote:
         | Yeah, agreed, this ain't it.
         | 
         | I do think theres room in the world for typescript to be able
         | to emit runtime code from its types, but I don't think it
         | should be in the business of writing validation libraries.
         | 
         | Closest they should get to this work is writing an interface to
         | export types types into runtime code that another lib can pick
         | up and write validators with.
        
         | tylerhou wrote:
         | Nit: they're not asking for runtime type safety; they're asking
         | for the ability to reflect on types (at compile time, to
         | generate values) so that they can use type information at
         | runtime.
         | 
         | This helps ensure runtime type safety because (for example) it
         | would be great to have a generic "validation" function that
         | takes an arbitrary interface and an arbitrary object and
         | validates that object. One way to implement this would be to
         | use /compile time/ reflection to generate code (TS code
         | hypothetical, because I write C++ nowadays):
         | function validate<T>(obj: Any): T | null {         switch
         | constexpr (T) {         case String:           return typeof
         | obj == "string" ? obj : null;         case Array<U>
         | if (!Array.isArray(obj)) {             return null;           }
         | for (const u of obj) {             if (validate<U>(u) == null)
         | {               return null;             }           }
         | return obj;         // ... more base cases         }
         | for (const prop: (keyof T) of Reflect<T>.Properties()) {
         | if (validate<T[prop]>(obj[prop]) == null) {             return
         | null;           }         }              return obj;       }
         | interface Date {         year: String;         month: String;
         | day: String;       }
         | 
         | It would be great if this could generate /JavaScript/ code:
         | function validate__String__(obj) {         return typeof obj ==
         | "string" ? obj : null;       }             function
         | validate__Array$Date$__(obj) {         if (!Array.isArray(obj))
         | {           return null;         }         for (const u of obj)
         | {           if (validate__Date__(u) == null) {
         | return null;           }         }         return obj;       }
         | function validate__Date__(obj) {         for (const prop of
         | ["year", "month", "day"])) {           if
         | (validate__String__(obj[prop]) == null) {             return
         | null;           }         }         return obj;       }
         | 
         | Unfortunately this is not possible (AFAIK) in TypeScript
         | currently, and will not be possible with TypeScript's current
         | philosophy.
         | 
         | (The above example is a hypothetical TypeScript compiler that
         | might support "templated" generic functions; with just RTTI
         | TypeScript could accomplish the same thing in a non-templated
         | function by passing in `T` as a function parameter at runtime
         | and doing runtime comparisons on `T`.)
        
           | TheRealPomax wrote:
           | Here's the thing though: if you wrote your TS properly, _you
           | don 't need this_ and asking for it just highlights that
           | you're not using TS the way it's meant to be used.
           | 
           | The only place you need runtime type enforcement (when you're
           | writing your own code in TS) is for validating third party
           | data at the point where you're ingesting it into your own
           | code. Once it's in there, _it is type safe_ if you used TS to
           | compile your code to JS, because your function calls and data
           | copies and everything else that moves data around was defined
           | in terms of compatible shapes.
           | 
           | And we already have runtime validation libraries to cover
           | that validation step. So many of them.
        
             | still_grokking wrote:
             | > Once it's in there, it is type safe if you used TS to
             | compile your code to JS [...]
             | 
             | To the extend that _TS 's type-system is unsound_, and
             | everything may crash at runtime at random anytime.
        
             | Nullabillity wrote:
             | That boundary validation is where that kind of reflection
             | would be useful! And it's a problem that (nearly) every
             | useful application has to face.
             | 
             | Well that, and getting rid of the silly "must be able to
             | strip types without processing them" design ideology would
             | also enable stuff like typeclasses.
        
             | ncallaway wrote:
             | > And we already have runtime validation libraries to cover
             | that validation step.
             | 
             | Right, but now my type information for inbound data must be
             | in two places: the typescript type, and the validation
             | schema. And heaven forbid I make a mistake and those two
             | become out of sync.
             | 
             | Yes, I can use something like zod to define a schema then
             | infer the type from it, but those inferred types are often
             | ... suboptimal to work with.
        
               | rizky05 wrote:
               | Zod is great, why do you think it is suboptimal ?
        
               | ncallaway wrote:
               | I like a lot of things about zod (it's what I use when I
               | need to do this kind of validation), but when I was
               | working with a mildly complicated schema the type that
               | z.infer<Schema> produced wasn't great for me.
               | 
               | When I produce a type definition for a nested schema,
               | I'll produce types for individual pieces.
               | 
               | So
               | 
               | type Schema = { foo: Foo; bar: Bar; baz: Baz[]; }
               | 
               | type Foo = { red: Color; white: Color; blue: Color; }
               | 
               | type Color = { r: number; g: number; b: number; }
               | 
               | type Bar = {...} type Baz = {...}
               | 
               | I couldn't find a clean way to decompose the type that
               | z.infer<Schema> produced. It would give me a single type
               | object that was deeply structured. For a pretty flat-
               | simple small schema, z.infer<> was totally fine.
               | 
               | For the more complicated schema it wasn't _terrible_, I
               | still used it. I made it work, but it definitely wasn't
               | the dev experience I was hoping for.
               | 
               | I think something that went the other way would be much
               | preferable for me. I'd rather define the typescript type,
               | then have some validate<Schema>() function that was
               | available to me.
               | 
               | Basically, I think it's _easier_ to get a generated
               | validate() function to play nicely with the rest of my
               | code, than it is to get the inferred type to play nicely
               | with the rest of my code.
        
               | solumunus wrote:
               | Use objectSchema.shape.xxx to access the nested schemas
               | and infer on those.
        
               | lf-non wrote:
               | I love zod and use it daily.
               | 
               | It is also the most frequent thing where junior
               | developers get stuck. TS tooling doesn't make it very
               | easy to work with large extracted types though it is head
               | and shoulders above other mainstream languages. The error
               | messages often become incomprehensible walls of text once
               | your types are Complex enough, and then tsserver will
               | just truncate the type info in pop overs making them
               | useless.
               | 
               | I am personally OK to live with all of the above. My
               | single issue with zod is that it is not easy to use if
               | you don't own your types. If your types are coming from a
               | third party lib you don't have an easy path to derive
               | runtypes from them. If the concept of runtypes was
               | supported by the compiler itself, this could have been
               | possible but as a userland library zod can't handle this
               | easily.
        
               | kristiandupont wrote:
               | Why would a ts-native offering produce better error
               | messages when it comes to complex types? That is an issue
               | with TS in general (or rather, with complex types in any
               | typesafe language).
        
               | lf-non wrote:
               | No.
               | 
               | Imagine a Zod schema like:
               | 
               | const UserLocation = z.object({ address: Address, coords:
               | Coords })
               | 
               | where Address, Coords are other zod schemas.
               | 
               | Now if I infer a type like:
               | 
               | type IUserLocation = z.infer<typeof UserLocation>
               | 
               | Th inferred IUserLocation is something like:
               | 
               | type IUserLocation = { address: { city: string, country:
               | string, ... }, coords: { lat: string, long: string } }
               | 
               | The extracted type does not refer to separate Address,
               | Coords type, it is a single complex type that represents
               | the complete nested structure.
               | 
               | So if I do something like:
               | 
               | const userLocation: IUserLocation = { address: { ... },
               | coords: { lat: 0, long: 0 }}
               | 
               | The error message is complex because it (effectively)
               | says that coords.lat was expected to be a string from
               | IUserLocation["coords"]["lat"] but it was number
               | 
               | However, if I define a ts interface directly:
               | 
               | interface IUserLocation { address: IAddress coords:
               | ICoords }
               | 
               | now any errors reported against this interface will be
               | more comprehensible because they will (effectively) say
               | that coords I am providing does not comply with ICoords.
               | 
               | This is a contrived example, but this becomes more
               | complex when you have deep compositions of zod types.
               | 
               | This issue of typescript not using well named
               | intermediate types when types are "extracted" from schema
               | definitions like zod _is_ what makes the error messages
               | complex.
               | 
               | This would not apply if typescript was to provide runtime
               | type checking for interfaces defined in typescript (as
               | opposed to them being inferred) because ts will have a
               | way to "know" about these intermediate types. Then the
               | type errors would not have to be always reported against
               | the complex top level type.
        
               | kristiandupont wrote:
               | That's a good point.
               | 
               | I just realized that I am working around this problem by
               | explicitly setting a `z.Schema<...>` type: https://github
               | .com/kristiandupont/kanel/blob/main/example/mo.... The
               | reason was to retain JSDoc comments on the types, but I
               | guess this was another positive side effect.
               | 
               | In any case, I agree with you that there is room for
               | improvement.
        
               | lf-non wrote:
               | Ah ok. However, typescript is mostly smart enough to
               | propagate comments [1] from zod schema properties to
               | inferred types on its own.
               | 
               | Thanks for maintaining kanel btw. We used to use this in
               | a previous role alongside knex. It was very useful.
               | 
               | [1] https://lorefnon.me/2022/06/25/generating-api-docs-
               | for-zod-t...
        
               | kristiandupont wrote:
               | Hah, I wasn't aware! I think that must have been fixed
               | after I tried it the first time because I definitely
               | concluded that it was necessary back then. And thank you
               | for the kind words!
        
               | cjdell wrote:
               | I found Zod a lot easier to use once we were given the
               | "satisfies" keyword. I still basically have to write my
               | schema twice (I don't mind this) but I can ensure the two
               | are tightly coupled. A change to either one will show a
               | compile error in the right place:
               | 
               | interface Person { firstName: string; lastName: string; }
               | 
               | const PersonSchema = z.object({ firstName: z.string(),
               | lastName: z.string(), }) satisfies z.Schema<Person>;
        
               | ncallaway wrote:
               | Interesting! I'll probably start doing that. I hadn't
               | connected the satisfies keyword to this problem, but it
               | seems like a good solution.
               | 
               | My complaint about writing the schemas twice isn't the
               | busywork (which is, like, annoying, but whatever I'll
               | live). But the concern about small discrepancies between
               | the two causing problems later.
               | 
               | I'll definitely use this going forward.
        
             | theteapot wrote:
             | > And we already have runtime validation libraries to cover
             | that validation step. So many of them.
             | 
             | Did you read the article? I think that's the point. The
             | premise is _Typescript_ should be responsible for solution
             | to runtime validation against _Typescript_ not third party
             | hacks.
        
             | thanzex wrote:
             | Except for the fact that usually there is not just one
             | single typescript agent working within itself, for which
             | you don't need validation. There are many cases in which
             | you need to verify some object, anything that does not come
             | from your code i would argue is untrusted, I come across
             | this almost daily, it would be absolutely fantastic to just
             | have a way to check _does this object conform to this
             | type?_ Instead, i need to use some external dependency,
             | effectively duplicate my type definitions and add yet
             | another place to introduce bugs.
        
               | IggleSniggle wrote:
               | Just use a run-type transformer like typia, hooked right
               | into typescript-compile. Get your runtime type validators
               | generated from nothing but the typescript definitions.
               | 
               | Alternatively, use a runtime validator the provides good
               | type inference out of the box so you're still only
               | declaring your types once.
        
               | JulianChastain wrote:
               | I would recommend `zod` as a good typescript schema
               | runtime validation library as well. It does require
               | strict type checking to be on however.
        
               | vendiddy wrote:
               | I use zod but it's a workaround. I use non standard
               | syntax to define types.
               | 
               | If typescript emitted type information, we'd be able to
               | automatically get runtime validation at the boundaries of
               | our apps.
        
               | mixedCase wrote:
               | Alternatively, io-ts is more performant and has been
               | around for a while longer. Although it does have a more
               | functional interface.
        
               | IggleSniggle wrote:
               | I like typia for doing codegen basically in the way this
               | request is asking: it hooks into the typescript API to
               | create runtypes from plain old typescript
        
             | moduspol wrote:
             | And presumably you need to also trust your third party
             | libraries, unless you're also compiling them from
             | TypeScript. Right?
             | 
             | And even if you are--that might also involve ensuring their
             | tsconfig.json is compatibly similar to yours. Otherwise the
             | compiler might allow them to return null instead of the
             | object they say they return, among potentially many other
             | "gotchas" that are bound to appear.
             | 
             | EDIT: Though I think I do agree with you, ultimately.
             | Runtime type checking imposes non-negligible costs and
             | complexity that still theoretically should be able to be
             | guaranteed at compile time for cases where one isn't
             | validating untrusted user input.
        
               | andix wrote:
               | Yes, you need to trust your third party libraries, better
               | check them. Otherwise they may steal your data, inject
               | XSS, mine cryptos, have memory leaks or faulty logic.
        
             | consilient wrote:
             | In a language with a sound (or even sound modulo escape
             | hatches) type system, I would agree. But Typescript can and
             | will lie to you at compile time, and it's much harder to
             | guard against this than it should be.
        
           | [deleted]
        
           | RyanCavanaugh wrote:
           | Not to be flip, but if it were really all this easy, we would
           | have done it already.
           | 
           | There are dozens of questions you can throw at this code:
           | What if the input's a union? What if it's a nested union --
           | how do you avoid combinatorial explosion? What if the input
           | is a function -- how do you validate its parameter types
           | using runtime information? What if the input is a conditional
           | type? What if you're inside a generic function? The list is
           | enormous and it quickly gets into "you've dug too deep and
           | unleashed a Balrog" territory once you get beyond the
           | primitives.
        
             | LtWorf wrote:
             | Given that several projects exist in python to do this... I
             | guess if you know about types at runtime, it is possible to
             | do it.
             | 
             | I write one of them (typedload).
             | 
             | If it's a union, it has a bunch of heuristics to guess
             | right at the 1st try, but otherwise it will just try them
             | all.
        
             | nonethewiser wrote:
             | > Not to be flip, but if it were really all this easy, we
             | would have done it already.
             | 
             | Typescript is mature. There is no low hanging fruit to be
             | develop.
             | 
             | I don't necessarily think it needs this but this is hardly
             | the right grounds to dismiss it.
        
               | afiori wrote:
               | I do not think that they mean that all easy things have
               | been done, rather that if this feature was easy then it
               | would already exist
        
             | pas wrote:
             | Maybe I'm very mistaken, but to me it seems this code
             | snippet is basically an alternative to writing a ton of
             | "infer"-s and overloads, no? So the same pattern matching
             | could be used in the "switch". Whatever the complier knows
             | can be locally matched, and the combinations have to be
             | already handled by the developer.
        
               | jitl wrote:
               | It's hard to come up with a compiler that produces a
               | sound checker for arbitrarily complex union/intersection
               | types. Perhaps there could be a restriction on reflection
               | to "simple enough" types, but that's always going to be a
               | weirdly moving target based on heuristics. There's
               | already cases where Typescript tries to generate ~40MB+
               | .d.ts files which are just re-stating the types
               | themselves. So it's easy to imagine a validator compiler
               | emitting 100MB+ of code to check more wild and crazy
               | types.
        
               | pas wrote:
               | Size, computation and other budgets seem like useful
               | knobs to expose to developers. And anything that's
               | locally decidable (so can be run on multiple cores
               | easily).
        
             | twosdai wrote:
             | Can we just start with primitives and see what happens.
        
               | bastawhiz wrote:
               | JavaScript already has this. It's called typeof.
        
               | galaxyLogic wrote:
               | And instanceof
        
               | jupp0r wrote:
               | Typescript purposefully influences this not at all.
        
             | oorza wrote:
             | Why don't you just make the transformer API stable, public,
             | and let the community do the hard part? There's plenty of
             | us that have experimental transformers doing all sorts of
             | fun things, these are problems that can be solved external
             | to TS.
             | 
             | I've got a fully functional compile-time dependency
             | injection container that I've been sitting on for literal
             | years because the transformer API isn't public.
        
               | code_biologist wrote:
               | ^^^ Please do this. I'm completely ok with "using
               | transformers voids your nonexistent warranty" and the
               | community can deal with transformer API churn. Exposing
               | the API makes it easier to adopt those community
               | solutions, versus me needing to explain to teammates why
               | I switched all the `tsc` invocations to `ttsc` and
               | promise it's not that sketchy.
        
             | KnobbleMcKnees wrote:
             | It is easy. It's just a terrible idea.
             | 
             | (So as it turns out having thought about it a bit, I am
             | vehemently against this idea.)
             | 
             | Type reflection at runtime would require polluting the JS
             | environment with a lot of cruft.
             | 
             | That might be a global object and lots of helper functions
             | to query types. It might also be tagging objects and fields
             | with additional properties that need to be treated as
             | reserved.
             | 
             | There is certainly no way to do this that doesn't make
             | assumptions about the runtime environment in a way that
             | will cause a mountain of issues further down the line.
             | 
             | The other reason for my disdain is: the need to infer types
             | at runtime is almost certainly indicative of an
             | architectural issue with your code. If you aren't able to
             | write viable code in a given context without requiring
             | runtime type querying then you should step back from your
             | intent and re-evaluate your code structure.
        
           | golergka wrote:
           | I just declare these structures with io-ts, and get
           | validation, serialization, deserialization code and types for
           | free.
        
           | paxys wrote:
           | I still don't see the point. There is a long list of
           | libraries that do exactly this, and do it well enough. The
           | author has linked to them himself. The overall benefit of
           | this would be _maybe_ slightly better syntax for these
           | libraries (even that is doubtful, because plenty of them
           | already have a `reflect <T>()` interface), but still zero
           | runtime benefit. And getting it to be accurate for 100% of
           | cases would entail exactly what I mentioned - writing an
           | entire runtime to do this inference.
        
             | Nullabillity wrote:
             | So now you're stuck writing for an awkward inner platform
             | language rather than using the TS syntax itself.
        
               | paxys wrote:
               | What's this "awkward inner platform language"? They are
               | asking for a `typescript.generateRuntimeType<T>()`
               | function to be native to the language. Well plenty of
               | libraries provide _exactly_ this syntax today. Here 's
               | tst-reflect: `const type = getType<T>()`. Notice any
               | difference?
        
               | Nullabillity wrote:
               | But tst-reflect seems to work by effectively building
               | their own forked tsc compiler.
        
               | paxys wrote:
               | No, they have a plugin into the typescript compiler which
               | uses their API. tsc already exposes all of the info they
               | need.
        
               | Dylan16807 wrote:
               | Okay so it's not a forked compiler but it's adding a
               | feature to the compiler.
               | 
               | At which point it makes a lot of sense to ask why that
               | feature shouldn't be merged.
        
               | auggierose wrote:
               | Because of feature creep. I don't need that feature.
               | Don't merge things that can be kept separate. It is
               | called modularity.
        
               | Nullabillity wrote:
               | According to their (tst-reflect's) README, tsc doesn't
               | support plugins. The plugin support comes from a fork
               | called ttsc.
        
               | andix wrote:
               | Wow, i didn't know that this is already possible with
               | type script. seems like there are transformers you can
               | add to typescript that can implement it.
               | 
               | So type script more or less supports the feature they
               | asked for. Just not bundled with the main package, but
               | they provide the interface to get it done with 3rd party
               | transformers.
        
           | scotty79 wrote:
           | If that's so much needed I wonder why there isn't a thriving
           | ecosystem of pluggable typescript preprocessors that add
           | whatever values based on types direcly to typescript source
           | before compilation.
        
             | andix wrote:
             | There are a lot, and some are mentioned here in the
             | comments.
        
           | andix wrote:
           | It would be great if McDonalds would serve first class sushi,
           | and pizza, and seafood, and pasta, and steak, and if they
           | would deliver frozen meals, and iron your laundry, and ...
           | 
           | They just serve burgers and fries. And they are doing very
           | well with that strategy. Same goes for TypeScript.
        
         | cjdell wrote:
         | TypeScript does emit runtime type information through enums
         | though.
        
       | Tade0 wrote:
       | We have types at home.
       | 
       | My litmus test regarding whether I can even consider using a
       | library in production is: does it have more stars than
       | fartscroll.js?
       | 
       | https://github.com/theonion/fartscroll.js/tree/master
       | 
       | Most of the entries there are below that number, which begs the
       | question: is this really that much of a problem that it mandates
       | the drastic changes required?
       | 
       | I actually don't know if it's even doable, considering TS's
       | structural type system, where the answer to the question "what
       | type is X?" is not straightforward.
        
       | lucidone wrote:
       | OP and those who feel a similar sentiment should give C# a shot,
       | it's what they want regardless of whether they know it or not.
        
         | anonzzzies wrote:
         | Yep, but you want to write frontend with it then. Blazor (or
         | whatever liveview-like implementation) or wasm might fix that.
        
         | shortrounddev2 wrote:
         | I love C#. At work, when I write standalone tools, I always do
         | them in C#. My boss tolerates this since I'm usually the only
         | one using them. But I don't get to choose what our backend is
         | written in
        
       | marcelr wrote:
       | Please no, typescript is already complex as all hell.
        
       | [deleted]
        
       | dSebastien wrote:
       | Runtime type checking is an explicit non-goal of TS:
       | https://www.dsebastien.net/2020-04-25-typescript-non-goals/
        
       | can16358p wrote:
       | This shouldn't happen... unless someone finds a way to do this
       | without a runtime overhead, which naturally seems impossible.
       | 
       | If this is done, TS will become something entirely different as
       | it currently doesn't have a runtime: it's a huge-and-smart
       | linter.
       | 
       | But that's all about it. No matter how huge, it's a linter.
       | 
       | Reflection would imply something beyond that. Even though I
       | absolutely love reflection, I believe it should not be integrated
       | into TS.
        
         | mrkeen wrote:
         | No runtime necessary, if I understand the problem.
         | 
         | Input is bytes. Bytes will never carry their type information
         | (and if they did, you couldn't trust them). So the type
         | information needs to be used in the Deserialiser, not its
         | input.
         | 
         | To get typed deserialisation of Foo, the compiler needs to
         | generate a FooDeserialiser automatically for you. The compiler
         | can't depend directly on Foo (Foo is written after the
         | compiler), but if Foo could somehow emit its type information
         | during compilation, then the compiler could depend on _that_.
        
           | can16358p wrote:
           | Then I'm all in. I thought something done at runtime
           | dynamically, instead of statically genereting type
           | information at compile time.
           | 
           | It'd be lovely the way you described.
        
         | vbezhenar wrote:
         | It has nothing to do with any runtime.
         | 
         | You just write                   const personType: Type =
         | typeof(Person);
         | 
         | This code gets compiled into                   const personType
         | = {           name: "Person",           fields: [             {
         | name: "lastName", type: "string" },             { name:
         | "firstName", type: "string" },           ],         }
         | 
         | There's no runtime. It's just an object which describes layout
         | of some time.
         | 
         | If you would implement validation by hand, you'd come up with
         | absolutely conceptually identical code. Look at any validation
         | libraries out there.
         | 
         | The only difference is: you specify types with nice TypeScript
         | language, not with some made-up abomination DSL.
        
           | can16358p wrote:
           | Oh okay I was thinking of more of a runtime-code-emitting-
           | dynamically kind of thing.
           | 
           | If it's the way you've shown it'd be great!
        
       | orangepanda wrote:
       | I vaguely remember one of typescripts developers stating that if
       | they had to start it all over again, enums would not be added; as
       | enums are the only thing emitting runtime code.
       | 
       | Typescript does not change runtime behaviour, there is no special
       | typescript {#if}
        
         | ragnese wrote:
         | > I vaguely remember one of typescripts developers stating that
         | if they had to start it all over again, enums would not be
         | added; as enums are the only thing emitting runtime code.
         | 
         | It's true. I don't remember if that was the only/main reason
         | they said that, but that was definitely one of the things.
         | 
         | I find that a weird sentiment, though, because TypeScript has a
         | couple of other features that are not just "JavaScript + type
         | annotations".
         | 
         | Namespaces is one. It also has a syntactic sugar for defining
         | class properties in the constructor arguments. And it had that
         | experimental decorator feature for a long time, but I never
         | used it, so I don't know much about it. It also has the "`this`
         | parameter" syntax for methods/functions, which does disappear
         | at compile time, but still _looks_ and feels like more than
         | just a JavaScript function with type annotations.
        
           | WorldMaker wrote:
           | From my understanding, namespaces are on the same list with
           | enums of things that the developers regret ever adding to the
           | language but can't take out without breaking old code.
           | Namespaces also at least have the excuse of being a
           | "necessary" jQuery-era "Production pattern" in the land
           | before ESM was standardized and somewhat relating to the
           | similar syntax sugar of import/export when generating AMD,
           | UMD, and CommonJS modules.
           | 
           | So too are "experimental decorators" another thing that some
           | of the developers seem to list as massive regrets. That
           | example is even so much worse than namespaces because it
           | wasn't justified by existing patterns used in Production JS
           | at the time _and_ that they even believed that requiring a
           | compile-time flag with the word  "experimental" in it would
           | _stop_ developers from using that compile-time flag in
           | _anything_ destined for Production usage. (Seriously, we all
           | should shame the many projects /companies that did that.)
        
           | wvenable wrote:
           | Although namespaces are not deprecated they are not
           | recommended anymore -- much for the same reasons.
        
       | evmar wrote:
       | If anything, the wide range of different approaches to run-time
       | type information listed here is pretty good evidence that there
       | are many different use cases and any approach built in to TS
       | would not cover them all.
        
       | haskman wrote:
       | A lo of people in this thread seem to be misunderstanding what is
       | being asked for. There is no runtime reflection needed. What is
       | really needed is -
       | 
       | 1. A way to get a value that represents the _type_ of any
       | statically known type (i.e. known at compile time). 2. A way to
       | compare two typereps for equality. 3. A way to convert between
       | types if the typereps are equal.
       | 
       | This is basically the equivalent of the `Typeable` class in
       | Haskell and PureScript
       | (https://hackage.haskell.org/package/base/docs/Data-
       | Typeable....). Both Haskell and PureScript erase types at
       | runtime, so it is possible to do without adding a runtime to
       | TypeScript as well.
        
       | drtz wrote:
       | The problem with TypeScript isn't the lack of reflection. The
       | problem is that at runtime its type system is still Javascript in
       | all its glory. Workarounds are just band-aids on the underlying
       | mess at best.
        
       | kazinator wrote:
       | Anything run-time has to come from JavaScript.
       | 
       | TypeScript is syntactic expansion layer over JavaScript.
       | 
       | "C preprocessor, please give me arrays that know how big they are
       | at run-time. Oh, and access to the calling function's local
       | variables!"
       | 
       | "Common Lisp defmacro, give me continuations usable anywhere!"
       | 
       | A macro layer can bring you the pie in the sky, but only (1) at
       | some nonozero cost and (2) with additional representations that
       | are not understood by regular code that is not in that framework.
       | 
       | Suppose a TypeScript type object is attached to every run-time
       | object created in TypeScript. Firstly, those objects become more
       | bloated and expensive to construct. [Edit: not really: all
       | objects of the same type can have a pointer to the same meta-data
       | which is created once]. They will need run-time support in their
       | execution environment in order to have those type
       | representations. Objects not created by TypeScript-generated code
       | will not have anything like that attached to them, so places in
       | the system where the two domains interoperate won't be able to
       | rely on reflection; it will need a fallback for objects that
       | don't do reflection.
       | 
       | I think serialization can be done without reflection. Because at
       | the time when the static language is being processed, you could
       | annotate certain types as requiring serialization. Then for those
       | types, TypeScript would generate the marshaling routines.
       | 
       | Generating marshaling stubs from an interface language has been
       | done in the C world for decades. It doesn't require any run-time
       | types. The generated marshaling stubs just know how to walk
       | objects of the type that they handle, and that's it.
       | 
       | It looks like in TypeScript, serialization is just punted to
       | JSON, which is inadequate because when we are deserializing, we
       | want to check that the JSON blob has a type and shape compatible
       | with the TypeScript-level type. (Or even for that that type to be
       | inferred in some way.) There are some libraries that try to do
       | something in this direction like ts-serializer.
       | 
       | I think it's something you really want in TypeScript itself.
       | 
       | Basically round up the half-dozen or so use cases for reflection,
       | and provide for all of them somehow without actual reflection.
       | It's an X/Y problem. People really want to do Y (e.g.
       | serialization), and believe that they must first solve X (have
       | metadata in objects for reflection).
        
       | medler wrote:
       | I'm mainly a backend programmer, so I know just a little
       | typescript, but I don't really understand what they're asking for
       | here. It sounds like they want to serialize and deserialize
       | typescript types automatically? If so, that sounds like a good
       | fit for a library, not something most languages offer. (Please
       | educate me if I'm missing the point)
        
         | jfengel wrote:
         | Javascript already has standard serialization and
         | deserialization tools.
         | 
         | The problem is that the deserialization is untyped. It's just a
         | Javascript object. Usually, the first thing you'll do is to
         | cast it to a typed Typescript definition, but there's no way to
         | guarantee that it actually fits that definition. No type
         | information exists at runtime. It's used solely to check the
         | code itself during compilation.
         | 
         | So any time you get data from outside of your program (over the
         | network, from a database, out of a config file, etc.) you just
         | have to hope that it actually fits the type. You can write code
         | to check it... but you have to write that code yourself.
         | 
         | There are libraries you can use. For example, you can use a
         | Data Description Language with a simpler type system, which
         | usually suffices for the kind of data you want to serialize.
         | Then you can use that to generate both a Typescript definition
         | _and_ a runtime type checker. But that 's inelegant, and not
         | standard, so every project is different despite it being
         | something everybody needs.
        
           | andix wrote:
           | It's basically the same for typed languages. If you want to
           | map JSON to a typed data structure, you need a serialization
           | library to do that.
           | 
           | JavaScript has a very simple built-in json reader/writer that
           | does no type checking and returns some nested dictionaries or
           | arrays. If you want more, you need a library (for example
           | zod). Or you just trust the data to have the right shape.
        
             | jfengel wrote:
             | Java has runtime type definitions, which you can use to
             | automatically type check deserialized objects. With
             | reflection you can write that in ordinary Java.
             | 
             | I imagine C# and other Java-esque languages have something
             | similar. But Typescript deliberately avoids that, and it
             | would be difficult to get it to do so.
        
         | shortrounddev2 wrote:
         | There is currently no good way to automatically validate the
         | object input to a typescript API. In the way that you can
         | simply specify the class of a POST body to a spring boot
         | controller or Asp.Net controller, every class in typescript
         | requires you write the type information twice: once for the
         | typescript compiler, and once again for the runtime
         | deserializer, in the form of decorators. Having to write extra
         | code to make up for a deficiency in your framework, runtime, or
         | language is the definition of code smell. As such: all
         | typescript backends which attempt to properly validate user
         | input are guilty of egregious codesmell.
         | 
         | Additionally, because it is impossible to emit these types to
         | the runtime, even in the form of a string naming the type, you
         | cannot validate input to an API using generics. If you have,
         | say, a class which will run a query for a record based on the
         | keys in that record:                   class Query<T>{
         | filter: Array<keyof T>         };
         | 
         | The typescript compiler can validate if a string in "filter"
         | is, in fact, a key of the class T. However, you cannot write
         | any decorator on this class to make the information of what
         | keys exist on T available at runtime. Therefore, to write such
         | a query interface and validate it at runtime, every record
         | which can be queried with this object must have its own
         | specific "[Record]Query" class written with its own decorators
         | to validate every possible input, usually with the valid keys
         | hardcoded into the decorator.
         | 
         | Because there is no real relationship between the class and the
         | runtime validators, this makes validation more error prone,
         | because it relies on either human beings to consistently
         | remember to add new fields to the relevant decorators, or a
         | custom linting tool to be written which basically pre-processes
         | the typescript source using the typescript API. This is, again,
         | writing code to account for the lack of features in the
         | framework.
         | 
         | WHY do we put up with this crap? We have had Java and C# for a
         | long time, and they solved these problems a long time ago. Why
         | are we writing Typescript on the backend?
         | 
         | The simple answer; it is easier to find javascript developers
         | than it is to find java developers. Bootcamps don't teach Java
         | or C# because there's more react jobs out there. Bootcamp grads
         | are not generally coding enthusiasts and so re-tooling is
         | difficult for them and they don't generally do it for fun. So,
         | we decided to write our backend in Javascript (or Typescript)
         | as a _labor_ decision, not a _technology_ decision.
        
           | mrloba wrote:
           | My experience is the opposite of yours. With typescript I use
           | an openapi spec to validate and generate types. For other
           | entry points I use typebox to create validators and generate
           | types. It requires a bit of work, but it adds a lot of
           | capability even beyond basic deserialization.
           | 
           | With c# I've seen openapi interface generators that don't
           | validate properly, only basic deserialization. I've seen
           | dto's that are deserialized wrong due to lacking null
           | checking attributes. I've seen the way put requests are
           | misused due to how difficult it is to separate null and
           | undefined in patch requests. I've seen dto's with all
           | nullables due to the lack of union types. Maybe I've yet to
           | see a good c# codebase, but I certainly prefer typescript
           | over the above.
        
             | shortrounddev2 wrote:
             | My preference is to have my types defined in code first,
             | rather than in markup language files which generate the
             | code. Having to rely on 3rd party code generation tools
             | because your language lacks a feature is, as I see it, code
             | smell. I'm not sure how to handle the scenario of undefined
             | fields in a PATCH, but I also don't tend to write APIs that
             | way
        
       | moritzwarhier wrote:
       | Very interesting post to me. There always was the argument that
       | TS should be erasable and carry no runtime information, enums and
       | decorators are a mistake, etc.
       | 
       | For what it's worth, I want my production bundle to be as small
       | as possible. Most people use bundlers among TypeScript, which
       | further complicates things.
       | 
       | I would love a _standard_ library to e.g. generate type predicate
       | functions from TS types.
       | 
       | Taming the beast from this end might even end up useful for
       | things like compilers, no?
       | 
       | TS provides a nice mechanism to be strict in the frontend and
       | validate types using runtime code, that is, type predicates.
       | 
       | But from a higher level, this has never been enough, and you want
       | to map JSON to TS types using some kind of schema definition.
       | 
       | I would love to just be able to pass in a TypeScript type and
       | generate its type predicate at compile time.
       | 
       | Unfortunately, this is impossible due to the halting problem.
       | 
       | So, a _standard_ solution for the case of a plain serializable JS
       | /JSON object and the according TS interface would be very much
       | welcome.
       | 
       | Edit: and all of this is of course about data from external
       | sources (requests, DOM, compiler...). For all of the code and
       | data known at compile time, there is rarely a need to validate
       | types, as they are statically analyzable.
       | 
       | So there is a huge scope that TypeScript has to cater to. It
       | includes JS projects where external type definitions often become
       | obsolete and people who code in TS but do not enable strict mode
       | for their own code (that is, disallow "any"). And all of these
       | type defintions have to be interoperable.
       | 
       | For API requests, this is basically calling for a default generic
       | REST client, and I agree that would be useful. The REST client
       | could use type predicate functions extensively.
        
       | [deleted]
        
       | anonzzzies wrote:
       | Thanks for this. I thought I was screaming into a void. I started
       | with typescript in 2018 and after two years started to believe
       | this is just not really a solution because what it is. I came
       | from Haskell/c#/f#, and TS, while it has a very powerful type
       | system, just doesn't give you much of the advantages the above
       | languages give you outside (some of) dev. Even when it does, it
       | is really limited in practice (aka when dealing with the real
       | world) vs, let's say, c#. You can defend from that somewhat,
       | however, you have to always keep the extremely (and that's
       | intended, but not what it could be) leaky abstractions in mind to
       | not run into bugs that shouldn't be possible in something that
       | claims static typing (if you don't know that it drops to js
       | without checks after compile).
        
         | seanmcdirmid wrote:
         | The point of TypeScript was always to run on web, it wasn't
         | meant to give you a language advantage over say, C#. You use C#
         | if you have to develop for .NET, you use TypeScript if you have
         | to develop for Web, you wouldn't use one or the other in
         | another context.
         | 
         | That being said, TypeScript is differently capable from C#. C#
         | is nominally typed, with decent reified generics. I like
         | programming in C#, and miss its features when programming in
         | TypeScript. TypeScript, on the other hand, is structurally
         | typed, forgoes soundness, and comes with a powerful type system
         | to express complex type relationships (again, possible because
         | it forgoes soundness). I like programming in TypeScript also,
         | and also miss its features when programming in C#. I doubt a
         | language that combined C# and TypeScript would be very nice,
         | these languages go in different directions to good effect, but
         | they are not compatible directions.
        
           | anonzzzies wrote:
           | But that's when you focus on the type system theory and I
           | agree with that. I don't see how enforcing types after
           | compilation has anything to do with a programming language
           | for the web vs 'not for the web' though, but I understand it
           | is the philosophy to check the types and then drop to plain
           | JS. Best tool for the job, sure, but literally losing
           | everything typed you wrote and designed after compilation is
           | just not as useful as it could (should imho) be. You express
           | whatever, it compiles, and then everything can break all that
           | you carefully set up, without any errors.
           | 
           | That's not the language or type system per se, it's the
           | compiler implementation or rather the philosophy to stay
           | close to js and have a very thin (powerful) layer at compile
           | time only. Typescript in wasm, Deno maybe (didn't try yet)
           | etc could change this. Then we can have types as in other
           | languages. Not sure why this would not be a win for everyone
           | vs the current status.
           | 
           | Also, as you know, the run the web went out the door with
           | nodejs; many backends are now typescript and indeed competing
           | (... for at least writing web apps) with c#.
        
             | seanmcdirmid wrote:
             | TypeScripts goal of being just a layer over JavaScript led
             | to its type system design being primarily productivity
             | based: the goal was to make programming nicer, using types
             | to get more performance wasn't a goal or option.
             | 
             | C#, and the CLR underneath it, were performance based, and
             | the types feed into that. The reason they both are as they
             | are is because of the environments they are meant to be
             | used in. So ya, are you running web apps on the CLR, or are
             | you running them in the browser. I don't really get nodejs,
             | or, i guess it only seems like you would go that route if
             | you wanted to reuse your web browser devs or web browser
             | code to run also in the server.
        
               | anonzzzies wrote:
               | Yes, and I am aware of the histories, we just want (and
               | need) something more now. Typescript still seems well
               | positioned for this. Not many reasons you cannot fix this
               | with a compiler flag (which is default off).
        
               | seanmcdirmid wrote:
               | You would have to change the entire type system to make
               | it C# like. TypeScript makes radically different
               | assumptions about static typing than C# does. It also
               | would be difficult to come up with a run-time type
               | representation that was even sensical (due to
               | unsoundness), let alone efficient. It isn't just a
               | compiler flag that you want, its an entirely new
               | language.
        
       | osigurdson wrote:
       | Reflection is terrible. The only thing that is worse is creating
       | something like reflection in imperative code in languages that do
       | not have it.
        
       | mk81 wrote:
       | [dead]
        
       | jmull wrote:
       | I'm kind of doubting the real value of this.
       | 
       | For validation, ORMs, APIs, etc., once you move beyond the
       | simplest cases, you need more information than is present in
       | Typescript type information. And that's before we get to the app-
       | specific concerns.
       | 
       | So you're going to end up with schemas, boiler-plate, code-
       | generators, and/or glue code anyway. Not to mention the libraries
       | to help manage this stuff.
       | 
       | It's not that it's completely unhelpful, but I think it's a
       | partial solution, and not the tricky part either.
        
       | nycdotnet wrote:
       | The TypeScript language service which powers IDEs and which is
       | maintained/shipped with TypeScript already has the knowledge of
       | all the types in your application. It seems like it would be
       | relatively straight-forward (though a lot of work!) to develop
       | some sort of code gen library that uses the TypeScript types
       | known to the language service to reflect on those types and emit
       | some sort of runtime type validation functions as part of a build
       | step. This could be done in an npm module similar to webpack or
       | in an IDE plugin. If that functionality doesn't exist today given
       | all the listed open source projects, I'm kind of surprised. I
       | don't think the TypeScript team would need to do anything to
       | allow such a project to be developed.
        
         | benatkin wrote:
         | It has quite an awkward way of being distributed. If you google
         | for standalone TypeScript language services you'll find
         | unofficial ones. Deno's is much simpler. Maybe they should
         | pioneer this.
         | 
         | Edit: Actually this is the first result, I hadn't tried those
         | exact terms. It's a bit hairy though, which is why the
         | unofficial typescript-language-server npm package wraps it.
         | https://github.com/microsoft/TypeScript/wiki/Standalone-Serv...
        
       | brundolf wrote:
       | 2C/, having non-runtime types makes code behavior easier to
       | reason about, especially when aggressive type inference is
       | present, and I'd hate to lose it
       | 
       | One of the things I don't love about Rust is how type inference
       | affects program behavior in ways that can be really subtle. In
       | Rust's case this is a necessary evil because it doesn't have a
       | dynamic foundation, but TypeScript has done great without that
       | compromise
        
       | LispSporks22 wrote:
       | I've heard the same complaint about Elm
        
       | lolinder wrote:
       | > Type erasure is good! It means JavaScript project can consume
       | TypeScript projects without any knowledge of TypeScript. It's
       | just emitted JavaScript. This does not mean you can't emit the
       | type information separately in a consumable lookup table that's
       | separate from the code. The lack of this type information means
       | we use esoteric libraries which ultimately pollute the JavaScript
       | with all the convoluted typing working arounds... soo... type
       | erasure has defeated the purpose of type erasure. It's a second
       | order effect, where the design goal defeats the design goal. :(
       | 
       | I think the author misunderstands the design goals of TypeScript.
       | The goal isn't to have pristine, beautiful JS code with no
       | complexity, the goal is to have the runtime semantics of
       | TypeScript be identical to the runtime semantics of JavaScript.
       | Barring the regretted exception of enums, TypeScript can be
       | converted to JavaScript by simply stripping type annotations.
       | _That 's_ the design goal, and that goal is not in conflict with
       | itself.
       | 
       | The ecosystem that has built up around TypeScript depends on
       | complete type erasure, and much of it would evaporate if this
       | wish were granted. TS support in ESBuild, Deno, and Bun would
       | become nearly impossible, because each would need to re-implement
       | all of tsc in their respective languages, while right now they
       | just need to maintain their own simplified parsers.
       | 
       | On the other hand, the convoluted libraries that OP bemoans are
       | perfectly compatible with all of these tools, because they're
       | implemented in user space.
        
         | shortrounddev2 wrote:
         | There are plenty of ways to emit runtime type information
         | statically without a runtime. `keyof` could statically convert
         | to the list of keys in a class. Hell, even typescript classes
         | could do what ES6 classes do and initialize class keys to
         | undefined. Currently, typescript classes erase all keys unless
         | explicitly defined. Object.keys() on a newly instantiated
         | typescript class without set members will return nothing, while
         | an ES6 class will return all of the keys. Just an option in
         | tsconfig.json to convert TS classes to ES6 classes (or just
         | allow ES6 classes to exist at the same time in Typescript)
         | would make some code generation WAY easier.
         | 
         | Or some kind of syntax to emit the name of a type as a string.
         | Currently, if you run `typeof foo` it will return the type as a
         | string. If you could have a static version of that, like
         | `tstypeof foo`, or with a class:                   class Foo {
         | bar: string;         };              console.log(tstypeof
         | Foo::bar) // or something less C++-looking; compiles to
         | "string".
         | 
         | then it would be killer. This could break compatibility if you
         | change the type of a field and a compiled client using the code
         | were to expect "string" when it's been changed to "number". But
         | I'd rather live in that world than the one we live in now
         | 
         | Just some _basic_ RTTI would make a lot of ugly codesmelly
         | boilerplate Typescript code evaporate instantly.
        
       ___________________________________________________________________
       (page generated 2023-07-08 23:02 UTC)