8 ms·
What's really missing is a seamless ability to add runtime checks to TypeScript. Otherwise, between Flowtype and TypeScript, static type checking is a solved pr
by gajus 4y ago
What's really missing is a seamless ability to add runtime checks to TypeScript. Otherwise, between Flowtype and TypeScript, static type checking is a solved problem in JS.
Hegel is basically a less mature version of Flow. I preferred Flow over TS for the longest time, but let's face it – TS won in terms of absolute adoption, with very little prospect for anyone to take over.
- hermanradtke 4y agoYa, something like zod needs to be part of the language.
- eyelidlessness 4y agoIt is! Zod is great. I don’t mean to undersell its value. But it’s more of a reference manual of how to effectively use the language features it uses, than something novel filling in gaps in the language.
- lf-non 4y agoI don't understand what this means. Any sufficiently valuable general purpose library (which zod is) is a candidate for first-class inclusion in the language if it is useful for a sizeable majority of the language's audience. Zod is filling a gap in the language - runtime type checking. It is not the only one doing so, but the fact that there are several such solutions clearly indicates that there is a general need for it.
- eyelidlessness 4y ago> I don't understand what this means. Any sufficiently valuable general purpose library (which zod is) is a candidate for first-class inclusion in the language if it is useful for a sizeable majority of the language's audience. The language doesn’t have, or at least makes not having a primary goal, any runtime. “The” language is JavaScript. TypeScript is just annotations of it. Really good annotations. So good that you can build them out of reliable runtime checks which are type guards, without even writing a single type definition except to infer from them. Zod is filling a gap in JavaScript. TypeScript is facilitating that.
- lf-non 4y agoI don't disagree with anything you are saying. However, what is or isn't the goal of a language is subject to change. Libraries like Zod are trying to filling a gap in js, sure. But we are arguing that that gap is better filled by the typescript - if that requires expanding its goal or doing things that don't fit in current scope - so be it. As to why it is better: Currently using zod requires that the author of the types uses zod's API. If they didn't anticipate that the types they are writing would need runtime checks, or prefer some other schema validation library than the one you prefer - as a consumer you need to now redefine all of these types using zod and keep them in sync. Compiler can help, sure but its still quite some work. If typescript supported this natively, you could import some random library and use its types for runtime validation - that is not possible today, and it can't be possible until ts has first class runtime type validation. People would also not have to learn the ts syntax and then also the zod api to achieve it. Languages like dart demonstrate that this is practical.
- CodeAndCuffs 4y agoFp-ts adds some amazing functional tools. Io-ts, which is built off of it, adds great run time type validation. I can define types using io-ts, infer a true typescript type from that to put in my d.ts files to get full ts type checking, and also have run time type checks, all from the same single definition. The initial learning curve is admittedly a little steep, but once you have it down it's a breeze to use, and delightful.
- btown 4y agohttps://deepkit.io/ https://deepkit.io/ may be of interest to you! It deeply patches the TS type compiler to make all types visible at runtime, enabling a lot of annotation-style workflows and dependency injection possible completely within the type annotation system: https://docs.deepkit.io/english/runtime-types.html https://docs.deepkit.io/english/runtime-types.html Previous discussion: https://news.ycombinator.com/item?id=31663298 https://news.ycombinator.com/item?id=31663298 - it's downright mindblowing that all this seems to be the work of primarily a single developer. For a less intrusive solution, https://github.com/jquense/yup https://github.com/jquense/yup is a great library to reach for whenever you're defining the shape of a network-transmitted object and don't want to introduce compilation stages.
- eyelidlessness 4y agoThere’s a seamless ability to add runtime checks in TypeScript and has been for a long time: type guards. It’s not built into the type system because no one actually wants that in TS or any other language, even when they think they do, at least without control over when it’s used. That is type guards. What everyone who asks for runtime checking actually wants is: - define once - declaratively - with clear validation and deserialization at boundaries where data types aren’t known - without overhead for internal types which are well known - without an additional build step like codegen That is type guards! They just have to be granular and composable, and well tested at a granular and composable level. Libraries like zod and io-ts have shown how to do it. You can just use them, or many others like them, you don’t need anything new. Or you can pretty trivially build your own custom solution if they don’t scratch your particular itch. You aren’t missing seamless runtime checks. You’re just not using them.
- yazaddaruvala 4y agoThe GPs request is a very fair one. Typeguards are 10% of starting the solution. What everyone wants: Autogenerated type guards by class. What everyone gets: “Remains out of scope.” and need to use other libraries. The compiler can do this significantly better (more ergonomic, less time, etc) than 3rd party libs. TS devs really should reconsider this feature. https://github.com/microsoft/TypeScript/issues/15265 https://github.com/microsoft/TypeScript/issues/15265
- eyelidlessness 4y ago> What everyone wants: Autogenerated type guards by class. I’m quite sure people are asking for that, but I’m quite sure they’d regret wanting it if they got it. To the extent it’s desirable, it’s a thing that should be in TC39, not in TypeScript. The wailing and gnashing of teeth over when or whether or how type coercions happen is already mythical for the underlying language. Adding it to a compiler that’s increasingly not used to compile but only to type check is gonna add ten years of gripes about JS tooling nonsense to every single discussion. They have considered this feature. Type guards are the solution and they’re a really good solution given the circumstances.
- 4y ago
- purplerabbit 4y agoSeamless runtime checks are fully supported via zod. https://github.com/colinhacks/zod https://github.com/colinhacks/zod You’re welcome. (I use this library every day. It has changed my life.)
- ar-nelson 4y agoIn the same vein, shameless plug for my own library, Spartan Schema: https://github.com/ar-nelson/spartan-schema https://github.com/ar-nelson/spartan-schema It does the same thing as Zod, but is much smaller/simpler and its types always have a JSON representation.
- deleted 4y ago[deleted]
- kotlin2 4y agoThere is a typescript library called runtypes which offers really great runtime type checking. It’s a vanilla TypeScript library, so it doesn’t require any modifications to your tool chain. It provides library functions for defining types that are very similar to how you’d define the types in typescript. Once you define the types via library functions, the library has offers access to the underlying TypeScript type using typeof and also provides checked JSON deserialization methods.
- hermanradtke 4y agoThere multiple libraries like this and gajus is well aware of them. They are libraries instead of being part of the language.
- kotlin2 4y agoYes, runtypes is not the only option. But the point is that TypeScript’s type system is powerful enough to implement runtime type checking. I’m not sure what the benefit would be to adding the concept as a first-class citizen in the language.
- hermanradtke 4y agoIf the typescript compiler included hygienic macros then you could implement something like Rust's serde crate. Once you have that, then you can write normal looking typescript interfaces paired with a macro that implements runtime parsing of an unknown value. For example: import macro { Deserialize } from 'ts-serde'; // I made up "import macro" syntax import { parse } from 'ts-serde'; #[Deserialize] // I borrowed this syntax from Rust interface Foo { bar: string; baz: number; qux: Record<string, string | null>; } Now I can do something like: const response = await fetch('https://www.example.com'); const foo = parse<Foo>(await response.json()); This is a much nicer typescript world to live in. I can use vanilla interfaces (or even types). I do not have to learn a separate syntax for runtime checks (such as zod, io-ts, runtypes, etc). If I want to switch from one macro implementation, my scope of changes is the annotation on the interface and the "parse" function. That is much, much easier than switching from io-ts to zod.