[HN Gopher] From TypeScript to ReScript
___________________________________________________________________
From TypeScript to ReScript
Author : ingve
Score : 114 points
Date : 2022-01-12 07:59 UTC (15 hours ago)
(HTM) web link (www.greyblake.com)
(TXT) w3m dump (www.greyblake.com)
| ronenlh wrote:
| Amazing in depth overview.
|
| There are useful comments in my (shameless plug) post about my
| same transition:
|
| https://news.ycombinator.com/item?id=25845147
| elevader wrote:
| > Despite requiring very verbose type annotations, TypeScript
| does not have a sound type system, meaning it does not guarantee
| the absence of type-related errors in runtime even if everything
| compiles fine.
|
| Does ReScript solve that? If so, how? In my experience this is
| mostly an issue with data/functions coming from outside sources
| (Return values from HTTP calls to endpoints you don't control
| being a big culprit). Sure, you can write type definitions for
| that but that doesn't mean anything unless everything is manually
| validated/checked at runtime as nothing really guarantees that
| the type definitions are actually correct. Does ReScript handle
| that automatically?
| chrischen wrote:
| At this current time rescript is still basically ocaml, and
| accepts ocaml syntax. So it has the Ocaml typechecker.
| ragnese wrote:
| That's not what soundness means in a type system. Of course
| untyped input has to be parsed and validated.
|
| An unsound type system means that you can write code that
| compiles, but experiences a runtime error caused specifically
| by the types (not the values or the business logic conditions)
| not actually being compatible. The famous example is having an
| array of a subtype being used as an array of the supertype:
|
| function doStuff(animals: Animal[]) { animals.clear()
| animals.push(new Cat()) }
|
| const dogs: Dog[] = [new Dog()]
|
| doStuff(dogs)
|
| dogs[0].bark() // <-- type error
|
| In a sound type system, that code would not compile because we
| know that you can't treat an array of Dog as an array of Animal
| in general.
| elevader wrote:
| I don't think that example would compile in TS either (not
| 100% confident though). The "issue" with TS is that
| everything type related completely disappears after the build
| step and that needs to be kept in mind in development. Some
| developers struggle with that, especially at the boundaries
| to external APIs/libs/whatever.
| the_gipsy wrote:
| For what it's worth, Elm does the runtime checks by means of
| forcing you to write "de/encoders" that must match the types.
| smt88 wrote:
| So does TypeScript if you have strict settings. Your input
| data will be untyped and you will be forced to determine its
| type before you use it.
| the_gipsy wrote:
| TypeScript does nothing like that with any strict settings,
| because it doesn't provide any JSON parsing alternative, so
| that is always unsafe.
|
| I bet there are runtime checkers that use some kind of
| reflection, that would be the next best thing. But I also
| bet that those force you to annotate/decorate everything.
| hermanradtke wrote:
| I do not know of a way to make this a compiler error:
| const user: User = JSON.parse(...);
| greyblake wrote:
| There still "weak" points, where incorrect typing can be
| introduced, e.g. incorrectly written bindings. Regarding data
| from HTTP call in theory they can be cast to any type abusing
| `external` keyword which is meant for binings. But common and
| recommend approach is to write codes. Codec would perform all
| the necessary checks to ensure that the data are in correct
| shape to satisfy the type restrictions. You can see some
| examples here: https://github.com/greyblake/from-typescript-to-
| rescript/blo...
| azangru wrote:
| None of the available alternatives to typescript -- Elm,
| Purescript, Reason/Rescript -- give me the same feeling of
| confidence in the future direction of these projects as
| typescript does. At least typescript is very closely aligned with
| the development of javascript; and it's also very widely used.
|
| - Elm: not general-purpose enough (only useful for UIs), plus has
| a tendency of making drastic changes between versions (remember
| how loudly people complained here? [0])
|
| - Purescript: the designer of the language, Phil Freeman, has
| stepped away from this project, and it doesn't seem to have
| gained sufficient traction
|
| - Rescript: I'm put off by its ocamlness; and worry whether it
| will repeat the trajectory of Flow, which has essentially become
| irrelevant
|
| [0] - https://news.ycombinator.com/item?id=22821447
| cardanome wrote:
| > Elm: not general-purpose enough (only useful for UIs), plus
| has a tendency of making drastic changes between versions
| (remember how loudly people complained here?
|
| Not really, it just has a slow release schedule. Over time it
| is relatively stable.
|
| Not a single thing has changed about it the last two years and
| the creator has communicated that it will probably stay mostly
| the same for quite a while.
|
| Yes, there have been some bigger changes in the past but that
| is fair game for software that hasn't hit version 1 yet and it
| was communicated that it might happen.
|
| The drama is mostly an issue caused by misaligned expectations:
| Many people assume that open source projects should be
| developed openly with everyone being able to contribute and
| having a say about the direction. Evan, the author of Elm,
| prefers to keep tight control of everything. The approach has
| some advantages and disadvantages and I can see why people
| might decide to stay away from the community but honestly if
| you just want to get work done in Elm, it is not much of an
| issue either way.
|
| Elm is probably the most stable and reliable choice for
| frontend code and helps avoiding the churn that happens in the
| JS ecosystems.
| fbn79 wrote:
| Idris 2 looks promising... I suggest keep an eye on it
| https://github.com/idris-lang/Idris2
| ostenning wrote:
| Reminds me of CoffeeScript, and look where that went.
| greyblake wrote:
| CoffeeScript is a language without static typing. Despite this,
| CoffeeScript actually made a real revolution when it was
| introduced.
| phaedryx wrote:
| They stole the good ideas from it and put it into ES6?
| draw_down wrote:
| blorenz wrote:
| Agreed. Though we did get the glory of fat arrows from that
| misadventure!
| codeptualize wrote:
| I've used Rescript (and ReasonML before that) for side projects,
| I really like it. I'd say it main strength is also its main
| weaknesses; it's not JS with a C# sauce (like TS), it's OCaml'ish
| with a JS sauce, making it really nice in many ways but also
| harder to pick up for JS folks.
|
| That's where Typescript clearly has the advantage; being just JS
| with types makes it much easier to get started, and the fact that
| its #huge also helps a lot.
|
| It's a bit sad as I think ReScript is much better on many fronts:
| the type system with crazy good inference and soundness, very
| easy to configure and add to existing projects (it just outputs
| JS files even with TS types), the module system is amazing (gone
| with imports) and creating simple bindings to existing JS/TS is
| also quite easy once you understand the basics, I'd go as far as
| saying it's easier than TS . It's also really fast, both the
| compilation as well as the JS it outputs.
|
| Because of the adoption hurtle I doubt it will be as big as TS,
| but I really hope it gains enough momentum and usage to just sit
| comfy in its niche, for that I think it needs to grow a bit
| further.
|
| I do think the ReScript team has made incredible progress on all
| fronts; I think ReScript is much easier to pick up than Reason,
| because of the language tweaks, but also the new website is so
| much better than the scattered docs in multiple places.
|
| I hope it will continue to improve and more people will give it a
| go!
| overgard wrote:
| I feel like the amount of time you would spend dealing with weird
| interop is far far greater than the number of times typescripts
| unsoundness would get you (hardly ever in my experience)
| Tade0 wrote:
| As a sort of litmus test I use the number of stars a superset
| of(or language compiling to) JavaScript has on GitHub and how
| that compares to fartscroll.js:
| https://github.com/theonion/fartscroll.js/
|
| By this measure ReScript is still a niche language.
| afavour wrote:
| I'm curious as to whether this is a good measure. I use a ton
| of modules and I don't think I've ever once starred a GitHub
| repo. I doubt I'm alone.
| Tade0 wrote:
| It's more of an appeal to language designers to not get too
| cocky too soon.
|
| After all if a joke script has more followers then it's
| better to tone down the marketing material.
| ltr_ wrote:
| very interesting language, I'm looking for a new programing
| language for our AWS lambdas, is ReScript a viable option for
| backends too?
| yawaramin wrote:
| Yes--if you target Node.js which I believe is supported first-
| class for AWS Lambda. ReScript compiles to very clean JS that
| looks almost hand-written. Should be easy to deploy to a
| lambda.
| asplake wrote:
| Interesting reference to Seed https://seed-rs.org/ - first I've
| heard of it. Anyone using it?
| greyblake wrote:
| Whatlang demo webpage is implemented with seed:
| https://whatlang.org/
| moritonal wrote:
| "This means having two files with the same name in different
| directories is not allowed."
|
| "ReScript has no async/await support."
|
| "ReScript has no special debugging support or source maps."
|
| Sorry but aren't these issues fairly glaring problems? They're
| hand-waived away because the project is small, but I feel like
| they'd become quite major eventually?
| Deukhoofd wrote:
| The first one is a design decision that I consider a bit "meh"
| as well, but I can see why they did it. The third one I'm
| assuming is just a thing that hasn't been gotten around to, and
| I think is reasonable to not immediately expect from a smallish
| project.
|
| The second one does sound like a fairly major thing though. The
| promise syntax shown in the article to get around the issue
| looks like a massive code smell.
| nicoburns wrote:
| Even just the first one would seem to make large projects a
| complete non-starter.
| frenchyatwork wrote:
| Just write in the style where all your names are like
| 'folder1/folder2/folder3/folder1Folder2Folder3Thing.ts`.
|
| (to be clear, this is sarcasm, please don't do this!)
| oauea wrote:
| Just don't use folders.
| awb wrote:
| I guess instead of:
|
| /index.res
|
| /posts/index.res
|
| You'd need:
|
| /index.res
|
| /posts/posts_index.res
|
| Pretty annoying
| ctenb wrote:
| You might be interested in trying PureScript as well. It has good
| FFI support and as a consequence there exist wellmaintained
| bindings into react etc. It can also run on other backends beside
| javascript, which makes that you can use it for backend
| programming too.
| ReleaseCandidat wrote:
| Yes, out of all alternatives I looked at, I did choose
| PureScript because of the (relatively) easy JS interop (which
| Elm lacks), not needing the JVM and having types
| (Clojurescript) and the better async handling without the need
| of `then`s and the function 'pyramids' and, last, but not
| least, the lack of (C-) JS-Style syntax.
| greyblake wrote:
| Thanks for your comment! I am aware of PureScript and even
| tried it a little bit 3-4 years ago, but was not aware that it
| has good interops too!
| throwaway81523 wrote:
| Yeah I also noticed Purescript was missing from your
| comparisons list. It's the only one of these that I've looked
| at much, and it seemed like the best of them, though I wasn't
| aware of the issue with ES6 modules. I don't use JS at all
| for now, so I haven't been up to date about anything in it.
| fbn79 wrote:
| I was looking to try PureScript but the lack of support for ES6
| modules still halt me from invest time in that language (see
| https://github.com/purescript/purescript/issues/3613)
| ctenb wrote:
| That's right, though that feature is very high on the
| priority list, so it's probably going to be supported fairly
| soon.
| shp0ngle wrote:
| > Unfortunately, today it's necessary to understand difference
| between OCaml, BuckleScript, Reason and ReScript to navigate in
| the ecosystem comfortably
|
| I got hit by this literally yesterday. It took me a while to
| understand this mess.
| cassepipe wrote:
| Yup, that's a rough start. I don't see how any project could
| take off with rebranding and splitting from an already small
| community, Reason users, (itself a split a relatively small
| community, Ocaml users). It seems like the road to success is
| the other way around. Make it a little better while super easy
| to adopt and iterate on that a la TypeScript or Reason, which
| can be considered alternate syntaxes for Javascript and Ocaml
| users respectively and are super easy to adopt whereas forking
| Reason into yet another programming language that has no
| ecosystem/community and wait for it to grow is almost always
| the promise of a bad pain/benefits ratio.
|
| A more thorough explanation of the whole kerfuffle :
| https://ersin-akinci.medium.com/confused-about-rescript-resc...
| dmitriid wrote:
| > there was a type mismatch, but the error the compiler reported
| was quite far from the original error made by me. It's not a
| compiler's fault, the fault was purely mine.
|
| No. No it's not. It's the compiler's fault.
| dllthomas wrote:
| Why not both?
| dmitriid wrote:
| Because it should be the computer's job to aid the user, not
| the other way around :D
|
| Though proper error reporting is quite hard and too many
| tools transfer the burden of figuring what happened to the
| user.
| dllthomas wrote:
| > it should be the computer's job to aid the user
|
| Most languages "aid the user" with better error locality by
| requiring the user aid _them_ with far more type
| annotations. Lack of error locality is presently a downside
| of relying on pervasive type inference (at least in both
| OCaml and Haskell).
|
| I expect there's room (and responsibility) to improve, and
| so I do accord the language some of the blame. But error
| locality can be recovered by adding back _some of_ the
| annotations that another language might require, and it can
| be _optionally_ deferred until the locality is desired. I
| don 't think it's right to say that that's requiring more
| help from the user than the baseline, and I think it's
| right to place some of the blame on the user misusing the
| tools if they're not adding enough annotations to get the
| kind of error locality they want from the tool they're
| using (as noted in the article, the author stopped doing
| that, although it may've been an overreaction).
| dsnr wrote:
| > TypeScript's type system is over-complex since it tries to be a
| superset of JS.
|
| This is exactly why it got so popular, and TypeScript support in
| the JS ecosystem is so good. It's easy to just strip the TS
| metadata and you're left with working JS. This is why projects
| like esbuild managed to ship TS support so quickly (without type-
| checking). Good luck doing that with a new language.
|
| I for one am "all in" on TypeScript, with all its shortcomings
| it's just the best of both worlds, and so easy to get on board.
| thegreatpeter wrote:
| ReScript supports Typescript types. Both consuming and
| generating them. Rescript also uses esbuild under the hood.
| Lots of great optimizations.
|
| If you're "all in" on TypeScript, you'll love Rescript. It's
| sooo much faster. Been using it for 3 years now.
| AkshitGarg wrote:
| ReScript doesn't uses esbuild. It has its own compiler:
| https://github.com/rescript-lang/rescript-compiler
| capableweb wrote:
| > It's easy to just strip the TS metadata and you're left with
| working JS.
|
| Compared to what? JSDoc made it even easier, you didn't even
| need to strip anything, as the "types" were just comments. This
| comes with its own problems, who want to program with comments?
| But it didn't require any changes to use for us who want
| nothing to do with TS.
| datagram wrote:
| > who want to program with comments?
|
| TypeScript supports providing types via JSDoc comments[1].
| This gets you use all the IDE language features you'd get
| using TS, including highlighting type errors. I actually use
| this all the time, since I have plenty of scripts that are
| complex enough that I want type checking but not complex
| enough to warrant a compilation step.
|
| There's also Google's Closure Compiler[2], which uses JSDoc
| for its JS type annotations.
|
| [1]: https://www.typescriptlang.org/docs/handbook/jsdoc-
| supported...
|
| [2]: https://developers.google.com/closure/compiler
| moonchrome wrote:
| What are the changes for people who don't want to use TS when
| they consume TS from JS ? The packages are shipped as JS with
| additional definitions.
|
| The stripping part is just a fallback option if you decide to
| move away from TS, you never actually use that in practice.
| Aldo_MX wrote:
| Comments have the potential to get forgotten and become
| incorrect. Type annotations not.
| cxr wrote:
| Corollary: we should invest in systems that allow us to
| mechanically verify correctness of comments as readily as
| type checkers do with type specifiers.
| verve_rat wrote:
| If you don't want to use Typescript... then don't?
| capableweb wrote:
| Yeah, duh. The argument is that there is a group of people
| who wants types and write libraries. Before they used
| JSDoc, which is effortless to use from JS, as it's just
| actually vanilla JS. Some of those started using TypeScript
| now for everything, including libraries. If I want to use
| those libraries, I need to fork the project and rewrite
| them to vanilla JS, something that was not needed before.
| Or find a different library/write it myself.
| elevader wrote:
| You actually don't, that's the nice part. NPM Typescript
| modules are shipped as transpiled js modules with d.ts
| files. Those d.ts files contain the type informations for
| consuming TS projects but they are completely optional
| and you can simply ignore them if you write a plain js
| project.
|
| You can see this in the babel project, for example. It is
| written in typescript but used by a lot of js projects
| that don't care (and don't have to care) about this.
| smt88 wrote:
| It sounds like you either don't use npm and are trying to
| use libraries' source files or you don't actually have
| this issue. This doesn't and can't happen with npm.
| mynegation wrote:
| > If I want to use those libraries, I need to fork the
| project and rewrite them to vanilla JS
|
| Why? If you want to just use, npm packages give you
| "compiled" vanilla JS and type definition files that you
| can ignore. Alternatively you can compile them yourself,
| if you vendor them in.
| ponyous wrote:
| > Good luck doing that with a new language.
|
| Compared to a new language...
| ragnese wrote:
| TypeScript's biggest flaw, IMO, is that it can't (or chooses
| not to- I don't understand anything about JS-adjacent build
| systems and how they work) understand the difference between
| "code I write" and "code someone else wrote".
|
| I'm not going to beat the dead horse of how unsound
| TypeScript's type system is. We all know that most of that is
| intentional because it would just be too inconvenient to work
| with existing JavaScript code (Aside: think about what this
| implies about existing JavaScript code. This makes alarm bells
| go off in my head).
|
| However, why should I have to deal with an unsound type system
| in _my_ new, fresh, TypeScript-only code?
|
| I'm not saying it's simple or criticizing anybody's work, but
| it would VASTLY increase my opinion of TypeScript if I could
| enable some kind of 'truly-strict-new-code' flag that would
| error on unsound code in the current project and maybe just
| warn when I _call_ unsound code from a dependency.
|
| Because, honestly, I'm truly disappointed that the one language
| that finally has a chance to unseat JavaScript has such a poor
| type system that it can't even do basic sub-type variance
| correctly no matter how many flags you set. Out of all of the
| statically typed languages I've used, TypeScript has helped me
| the least when it comes to type errors.
| WorldMaker wrote:
| > TypeScript's biggest flaw, IMO, is that it can't (or
| chooses not to- I don't understand anything about JS-adjacent
| build systems and how they work) understand the difference
| between "code I write" and "code someone else wrote".
|
| Arguably no language in the world makes that distinction and
| Microsoft's "Just My Code" debugger tools are fantastic but
| use a lot of heuristics that you generally tell get as many
| false positives as false negatives, which is likely why it
| would always be a toggle.
|
| That said, I do think Typescript _could_ make a better
| distinction about types that come in from code it has
| compiled itself (directly seen) and types that come by way of
| definition files with no code attached ( "hearsay" types).
| (Again, I can't think of any language today that trusts code
| versus symbols files so differently, so this would be a new
| thing.)
|
| Often I want it for the: I'm looking at the JS or its
| documentation right now and it would let me call it this way,
| but for some reason the Community types are too strict and I
| don't want to file a DT PR and get into some philosophical
| discussion about authorial intent versus JS as written versus
| documented examples and which is "most true" so I'm just
| going to have to cast this API to any for now and call it a
| day.
|
| But I can also see the point in: don't give me strictness
| errors outside of the fence of code you are compiling for me
| right now in this project. And maybe more unsoundness tools,
| such as option to treat all return results as `unknown` and
| force defensive coding when using outside APIs. In general I
| think `unknown` isn't used enough in community types (it is
| still "too new").
|
| Though `unknown` is also maybe _too_ defensive for a lot of
| commmunity types, too.
|
| Also, if you want to code that defensively, you could always
| replace community types .d.ts files yourself with ones that
| use a lot more `unknown`.
| ahuth wrote:
| I can't get behind the idea that a type system is either
| completely sound or completely useless.
|
| Surely preventing 99% of issues (or 90%, or 80%) is good?
|
| I'm also not aware of too many real-world instances of
| unsoundness in TS that has caused problems. Obviously I don't
| know your specific scenario, but it's possible there are ways
| to work with TS (instead of against it) to get a good level
| of type safety.
| jshen wrote:
| > Surely preventing 99% of issues (or 90%, or 80%) is good?
|
| You can't assume there aren't other trade-offs that you
| have to factor in to the analysis.
| ahuth wrote:
| You're totally right. Different teams and situations
| require different tradeoffs.
|
| While TypeScript is great for the tradeoffs I deal with,
| there are certainly others where it's not.
|
| Good call out.
| ragnese wrote:
| > I can't get behind the idea that a type system is either
| completely sound or completely useless.
|
| EDIT: I'm sorry. I thought you were someone else.
|
| [REDACTED]
| ahuth wrote:
| Can you link to where we previously discussed TypeScript?
| I don't remember that, and can't find it anywhere in my
| comment history (looked back to 2019).
|
| Also, I didn't mean to misinterpret what you said. Sorry
| about that.
| ragnese wrote:
| Yikes. I'm so sorry. I mistook your username for another
| one. That was incredibly rude of me to react like that
| without at least double-checking.
|
| I had a long and frustrating back-and-forth with someone
| else some time ago where I pointed out what I believe to
| be several glaring issues with TS's type system (like the
| fact that `readonly` properties on object types don't
| actually guard against writes in most situations) and
| every one of my criticisms was met with the equivalent of
| "You're saying a type system has to be 100% perfect or
| it's completely useless". And even though it's the
| internet and I should know better, it just irritated the
| hell out of me.
|
| Again, I'm really sorry for jumping at you like that. I
| think I'm traumatized over arguing about TypeScript...
| lol
| ahuth wrote:
| No worries. I made an assumption about what you were
| saying that wasn't helpful, either.
|
| All good!
| inbx0 wrote:
| By sub-type variance are you referring to issues like this
| https://stackoverflow.com/questions/47850513/unsafe-
| implicit... ?
|
| FWIW the lack of explicit variance annotations (and probably
| many other TS unsound design choices) are not so much related
| to supporting old untyped JS, but rather language design
| decisions that have to do with pragmatism and type system
| complexity.
|
| I can't find it now but I have a vague recollection Hejlsberg
| talking about the explcit variance annotations explicitly,
| how those were a huge can of worms in C# and they didn't want
| to bring them to TS. Unlike Flow, by the way, which does have
| explicit variance handling and doesn't suffer from the
| beforementioned foot gun (but does have its own foot guns of
| course).
| ragnese wrote:
| Yes and no. I do think that there are only two correct ways
| for a type system to do generic user-defined types: you
| either give us variance markers or you make all user-
| defined generic types invariant (Swift does this).
|
| Personally, I hate the latter, but not as much as I hate
| unsoundness.
|
| But, what I'm talking about is even more basic: https://www
| .typescriptlang.org/play?#code/MYGwhgzhAECCB2BLAt...
|
| The code I wrote there is actually wrong for two reasons:
|
| 1. Type variance
|
| 2. Readonly doesn't do fuck-all in TypeScript for object
| types
| inbx0 wrote:
| Yeah I agree, that's not what I'd consider good variance
| rules either.
|
| I guess my point was more about the reasons behind these
| weird rules. AFAIK interop with existing JavaScript was
| not the primary reason for doing them this way, if that's
| any consolation.
|
| FWIW your example wouldn't fly in Flow
|
| https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVBjGBDAzrsAQQD
| sBL...
| pcthrowaway wrote:
| Is it even possible for the program to know at compile-time
| if the types will be violated at run-time? Even if you
| declare data from other sources 'not mine' this still seems
| like it would be impossible to do.
| bern4444 wrote:
| As long as the data is from within the system, yes. If
| you're trying to use data from an external source (api
| request, external json file etc) than no, but that's true
| of most type systems.
|
| If you correctly type the response of that request then the
| answer becomes yes again.
| pcthrowaway wrote:
| Maybe I misunderstood, but I thought the person I was
| responding to was suggesting having the option for sound
| typing enforced in typescript, at compile time. Because
| if it's at run-time... well the run-time is Javascript,
| so there's of course no typing there. This isn't really
| on Typescript
|
| There are however javascript libraries which allow you
| specify object schemas and throw errors when mismatches
| occur. Perhaps the suggestion then is to build some
| shared layer between the TS compiler and V8 so that
| similar schemas can be autogenerated by the TS compiler
| and enforced at run-time.
| nesarkvechnep wrote:
| Take a look at Elm.
| danenania wrote:
| You can accomplish it with a library like zod[1]. It's not
| the prettiest though; first class support would definitely
| be better.
|
| 1 - https://github.com/colinhacks/zod
| ragnese wrote:
| > Is it even possible for the program to know at compile-
| time if the types will be violated at run-time?
|
| I mean, that's kind of the whole point of static typing,
| right?
|
| If you're speaking to TypeScript/JavaScript, specifically,
| then yeah, the compiler can't guarantee anything because
| someone can hop into the running program and start
| modifying objects as they please (at least for web page
| code).
|
| But the compiler _could_ still make the weaker guarantee
| that "the code that I can see is soundly typed". And for
| 99% of us that's effectively the same thing.
| jayshua wrote:
| The type system can force you to handle both cases - the
| data being in the expected & typed form, and the data not
| being in the expected form.
|
| You would have a function like this:
|
| parseJsonString : String -> Result Error Person
|
| Where Result is a value that is either an Error or a
| Person.
|
| To get the Person value out, the type system forces you to
| also do something with the Error if it exists. Not handling
| both possibilities in some way is a type error.
| armchairhacker wrote:
| I was just thinking about this. TypeScript's main flaw is
| that it's a full superset of JavaScript, which is a full
| superset of old JavaScript with weird conventions (null vs
| undefined, == vs ===). Furthermore, its type system is so
| strong it can type practically any JavaScript, but at the
| cost of strong typing.
|
| I wish there was language that was basically
| JavaScript/TypeScript, but it gets rid of backwards-
| compatible JavaScript edge cases and conventions (like, no
| more undefined, no more {} == '0', no more weird function
| 'this'), removes advanced types and makes the type system
| sound, and (just in case) can actually check typecasts and
| non-null assertions at runtime. JavaScript and TypeScript are
| honestly great languages, but they are great languages with
| major flaws in the name of backwards-compatibility.
|
| Even with strict typing enabled, I write a surprising amount
| of bugs which ultimately come down to type errors. And not
| only that but _silent_ type errors, because TypeScript's
| casts and not-null-assertions aren't checked. So often I find
| that a mistyped or null value managed to slip through a type
| guard without the compiler saying anything.
| sandruso wrote:
| Backward compatibility is bridge to whole JS ecosystem. If
| there was way use "unsafe" old js code within newer
| language that would be great. But it would bring another
| set of annoying problems.
| pjmlp wrote:
| Same here, by being a tool to type annotate JavaScript, it kind
| of avoids the usual guest language problem.
| elevader wrote:
| And it works in both directions. You can "easily" (I mean, this
| is JS afterall so this heavily depends on the degree of
| toolchain hell chosen) move to the TS toolchain and rename your
| files to have the .ts extension and you have a valid TS project
| and benefit from the inferred types for your code. Type
| annotations can then be added later on as you go. And the
| syntax everybody already knows stays valid. This is a huge
| benefit compared to something like ReScript because it makes
| adoption really easy. With the obvious downside of not having
| nice features like pattern matching.
| kvathupo wrote:
| I agree that TS eases the transition from JS, but I'd qualify
| your statement by saying it's not the toolchain that's a
| source of headache.
|
| Ideally, one should compile TS with `--strict`, otherwise
| there's little difference with JS. With this in mind, it's
| quick and easy to switch to TS tooling. Afterwards, one can
| incrementally adopt stricter typing, culminating in adding
| `--strict` to your `tsconfig`.
|
| In reality, since `--strict` is false by default, I'm
| concerned people erroneously assume that their JS code is
| type-safe after the first step, when it really isn't. In
| other words, it's no different than JS, except in name only!
| _old_dude_ wrote:
| The problem with the add types later approach is that in the
| end you have half baked .ts files left and right. And it
| becomes increasingly difficult to know when something
| compiles if it's because it's correct or because there is an
| any somewhere.
| elevader wrote:
| Yeah, agreed. Ideally this wouldn't happen like that.
| Temporary solutions like a half-migration have a tendency
| to stick around for a lot longer than anybody anticipates.
| But I think it is still better than not having any types at
| all, if only for having type information in development.
| frou_dh wrote:
| >It's easy to just strip the TS metadata and you're left with
| working JS.
|
| This actually touches on one of ReScript's supposed unique
| selling points amongst the functional compile-to-JS languages.
| Namely that the JS its compiler generates is so clean and
| readable that, if you end up deciding you don't want to bother
| with ReScript any more, you can just take the output from the
| final time you ran the compiler and treat that as a plain JS
| codebase to continue working on. Exactly how true that is, I
| don't know.
| jillesvangurp wrote:
| Typescript is a gateway drug for Javascript programmers. It's
| backwards compatible. So, it's easy to get started. However, it
| comes with a lot of compromises to enable that backwards
| compatibility.
|
| If you think of javascript as a compilation target rather than a
| language, typescript is just one of many languages that can
| target that. And I'd argue that even javascript these days is
| transpiled to what runs in the browser. It might be the same
| javascript dialect. But minified/obfuscated etc. But more
| commonly, it's more than just that. In short, modern javascript
| development involves transpilation/compilation. It just does. The
| whole scripted/interpreted vs. compiled distinction that people
| used to make is less relevant these days. It pretty much always
| involves some kind of compiler.
|
| And if you are going to use a compiler, you might as well use a
| proper one that does some useful stuff like prevent bugs, check
| types, optimize, etc. Typesystems have come a long way in the
| last 20 years. In short, there is no technical reason to be using
| Javascript exclusively in 2022. Whether it's Clojure, Elm,
| Kotlin, or other languages; they each have in common that they
| have js transpilers that work quite nicely and type systems that
| are definitely a level up from the unholy mess that is
| Javascript's "it could be a string or some object or undefined,
| but who the hell knows". Some people actually prefer that. Other
| people want no part of that kind of sloppy typing. And the good
| news is that there is no technical need to have any of that.
|
| I've been using Kotlin-js for the last year for a web
| application. The tool chain has some rough edges but the language
| is a joy to work with generally also for browser development.
| Definitely an upgrade over typescript, which I've also used in
| the past. And we have quite a bit of multi platform kotlin code
| that we also use server side. A lot of what we do is increasingly
| multiplatform and not explicitly dependent on the JVM. We could
| choose to use that code also on Android or IOS (via the native
| compiler). With compose web and other emerging Kotin web
| frameworks and the upcoming WASM compiler for Kotlin, I suspect
| it's going to become a lot more popular to use for web
| applications. With WASM, transpiling to Javascript will
| ultimately become a thing of the past. If you are compiling, you
| might as well produce WASM. Short term there are some open
| interoperability issues with browser APIs of course. However,
| nothing that can't be solved long term.
| greyblake wrote:
| +1
| smallerfish wrote:
| Have you had issues around the distribution size? I've been
| playing with building a kvision based app for the past year as
| a side project, and I can't get much lower than 2MB. I suppose
| I might try a "hello world" with compose web and see how that
| shakes out.
| jillesvangurp wrote:
| It's a concern but it has been getting better. Dead code
| elimination (DCE) in kotlin.js has improved in the last year
| as they rolled out support for the new IR compiler with 1.5
| and 1.6. It's still not perfect, but it's getting there.
|
| For what it is worth, we are using the Fritz2 framework,
| which is quite nice. That was definitely a bit of a bet a
| year ago but we've stuck with it and they are getting close
| to a 1.0 now. We might switch to compose web at some point
| but it looks a bit early for that right now. One plus point
| with Fritz2 is that it comes with a nice component library,
| support for themes, etc. So you can get up and running pretty
| quickly without spending a lot of time on custom component
| design.
| gdsdfe wrote:
| I've never understood why reason was rebranded into rescript, it
| felt like it killed the momentum behind it at the time
| pbiggar wrote:
| It's because Reason and Bucklescript were two separate projects
| with two separate goals. The goals of Reason was to be multi-
| platform, which was causing lots of technical challenges for
| rescript, which didn't care about that need but were doing most
| of the work. So the two needed to split up, and no-one had ever
| heard of bucklescript.
|
| Then the messaging on the name change was unclear, and the fact
| that Reason still exists (walking dead, but the name is still
| out there) made it all very unclear to everyone what was
| happening, and I think that caused a massive amount of damage
| to the momentum.
|
| But then again, it's a great language that's moving quickly, so
| I expect it will continue to grow. Certainly my company is
| built on it.
| skywal_l wrote:
| A couple of strange things:
|
| * the use of decorators in even the most basic example
|
| * no async/await. You fall back to Promise.{then,resolve}. The
| example given is not that clear to me.
|
| * You can't have two files with the same name in different
| folders??
|
| And in general, for me, the ability to be a little less strict at
| times makes Typescript way more easier to deal with. It's a 80/20
| thing. Most of the time I want type enforced but in some
| situation, I know it's OK and I just want to move on with my day.
| greyblake wrote:
| > the use of decorators in even the most basic example
|
| Can we agree that JSX is not a valid JS? So decorators are
| required indeed to simulate "JSX magic"
|
| > no async/await.
|
| As I mentioned, it's not an really an issue (although I though
| it will be). At least from my experience.
|
| > You can't have two files with the same name in different
| folders??
|
| This sucks indeed :)
|
| The problem that those 20% corrupt the value of another 80% :/
| [deleted]
| [deleted]
| MoSattler wrote:
| > Can we agree that JSX is not a valid JS?
|
| Neither is rescript - so why not make jsx a first class
| citizen?
| greyblake wrote:
| Because a programming language is not a template engine.
| scrollaway wrote:
| Neither is jsx. It's just syntactic sugar for some
| recursive function calls.
| yawaramin wrote:
| JSX is a first-class citizen in ReScript. No decorators
| required for JSX. Only required for React component
| function signature.
| ronenlh wrote:
| Typescript is "breath-first," you can convert your entire
| project to typescript in a minimal pull-request. Gradually
| adopting the syntax.
|
| ReScript requires a lot of commitment, as you have to
| completely rewrite each module to 100% comply with the type
| algorithm.
|
| Typescript even transpiles when it encounters type errors.
| greyblake wrote:
| You don't have to. You can have write a single component in
| ReScript and use it with the rest of the project written in
| JS or TS. See https://rescript-
| lang.org/docs/gentype/latest/introduction
| thegreatpeter wrote:
| Sorry but that's not true. You can adopt ReScript one file at
| a time. ReScript supports importing and exporting typescript
| types out of the box so you still get the type safety from
| "the other side"
|
| We started using Rescript by adopting individual files until
| most of our codebase is ReScript. We still have Typescript
| lingering around but folks _choose_ to refactor it to
| Rescript because they've found it easier to work with.
| knuthsat wrote:
| No async/await is a good thing, IMO.
|
| Using fp-ts there is never a need for async/await and the code
| is still linear, (Promise is transformed to TaskEither<Error,
| Result>, similar to the example in the article, although you
| can ignore the error and just map over the result, handling the
| error somewhere near the end of the chain).
|
| Problem with async/await is that the syntax is so easy that
| eventually the whole codebase gets polluted by it, even parts
| that could have been completely separated.
|
| From the coding perspective, the problem with promises arise
| when there is a need to bind the intermediate results. You can
| either store them in an object and return that object for the
| next .then(fn) call, or you can nest inside a promise. I guess
| nesting is what annoys people the most (pyramid).
| drenvuk wrote:
| Do you dislike async/await? If so, why?
| knuthsat wrote:
| I discussed it elsewhere in the thread.
| agumonkey wrote:
| I think I've heard that underneath, async/await gets
| desugared into a Task "monad" anyway.
| sergiomattei wrote:
| > Problem with async/await is that the syntax is so easy that
| eventually the whole codebase gets polluted by it, even parts
| that could have been completely separated.
|
| Curious, why is this bad?
| knuthsat wrote:
| Sometimes you don't want to pause (with await) and give
| something else the chance to execute (happens a lot in UI).
|
| When code is sloppily written you realize that at some
| point you can't use much of the existing code outside of
| async.
|
| One nice example of polluting the codebase is having async
| local storage. Now everything that reads from the storage
| needs to be annotated async and now your initialization
| pipeline might be insanely async. Good way to avoid it is
| to read the whole local storage at the beginning (having a
| sync interface) and then everyone just reads without await.
|
| From recent experience, I did exactly that with storage and
| ended up removing thousands of async annotations that were
| no longer necessary.
|
| Similar "mistakes" happen for other things and then at some
| point you are putting loading guards everywhere because
| your async operations are always awaiting and letting the
| UI update when it should not.
| skywal_l wrote:
| Behind async there is a real actual hardware reality.
| Accessing local storage (or the network) is slow and you
| do not want to block your UI.
|
| You say async were all over the place. Either it makes
| sense because fundamentally, what you are doing IS
| asynchronous. Or it make no sense because the
| asynchronous nature of you calls are not important in
| your design (I don't see why but ok), in that case you
| can always break the chains by using a promise:
| async bar() { return await baz(); }
| foo() { const promise = bar();
| promise.then(() => {}); // don't care... }
| knuthsat wrote:
| Yes, but the usual cases of -> "app starts -> load some
| state from local storage -> store it in memory for sync
| access -> do app" sometimes get lost due to the ease of
| async/await syntax.
|
| If you have to chain network requests but each request
| depends on results of the former ones, then async/await
| makes it really pretty.
|
| I have no idea how much async/await is too much.
|
| What I do dislike is that storage loads, network requests
| and other things are tied to the same type, so when you
| look at code, you have no idea what's happening inside
| those async functions, but that story is for some other
| time.
| thegreatpeter wrote:
| There are a lot of stranger things typescript makes you do make
| things work properly =P
|
| Rescript doesn't make you do strange things. The async/await
| stuff is annoying for sure, but after 3 years of using it,
| we've kinda forgotten about it.
| Asraelite wrote:
| > no async/await
|
| Doesn't this mean we're basically back to callback hell? This
| was one of the primary criticisms of Node before async/await
| was introduced.
| skywal_l wrote:
| Callback hell was before the introduction of Promises.
| Promises tried to abstract away the callback mechanism and it
| made things a little clearer, but you still had the pyramid
| effect of successive Promises.
|
| Await/Async kind of streamlined all this.
| dsnr wrote:
| I still somewhat prefer the readability of promises vs.
| await. I like the expressiveness of a then/catch as
| functions as opposed to try/catch blocks, which I've always
| disliked. But I agree that await is more suitable for more
| complex scenarios.
| nsonha wrote:
| async/await is just a syntax sugar, most languages didn't
| have it until very recently when it became a trend or
| something. In OCAML it's just like any other monad you use
| the bind operator instead. No need for special keywords.
| kevingadd wrote:
| C# 5.0 introduced async/await in mid-2013 (late 2012
| depending on how you count it), and F# had it before that
| in its version 2.0 (~2007). It's a pretty old "trend".
| nsonha wrote:
| anything else other than those 2? An idea that .Net
| started, could be good could be bad, but the .Net
| association isn't added credibility.
|
| async/await aren't keywords in F# and kotlin
| afavour wrote:
| > anything other than those two?
|
| Rust?
| nsonha wrote:
| I was arguing that languages are following the "add
| async/await" trend _recently_ , including rust. That
| other comment brought up that it exists in C# for a long
| time, hence not a recent trend.
| dharmaturtle wrote:
| https://en.wikipedia.org/wiki/Async/await#History
|
| F# in 2007
|
| C# in 2012
|
| Python in 2015
|
| Typescript in 2015
|
| Javascript in 2017
|
| Rust in 2019
|
| C++ in 2020
|
| Swift in 2021
| nsonha wrote:
| in F# it's an instance of computational expression, not
| keywords. So it's really only C# that added the keywords,
| and other languages followed suit since 2015. None of the
| functional languages have async/await as keywords
| sideeffffect wrote:
| I'm almost sure that Haskell has had its "do notation"
| even before 2007.
|
| And maybe even Scala its "for comprehension".
| dharmaturtle wrote:
| Yeah - I was limiting my post to explicit async/await.
|
| Don Syme, creator of F#, had a nice thread on the roots
| of async/await, though it doesn't mention do-notation: ht
| tps://mobile.twitter.com/dsymetweets/status/1407400817917
| 9...
|
| I'm still annoyed that most other languages stole
| async/await... but not the more general monadic/do
| notation. Instead we get elvis operators, chaining
| functions, etc.
| lolive wrote:
| I will probably be banned from any Haskell forum after
| that, but isn't the do notation a async, and the <- a await
| ?
| nsonha wrote:
| what do you mean by banned? You got it the other way
| around, async is a special case of the do notation, and
| await is the special case of <-
| Zababa wrote:
| It's basically that. Example:
| hello.then(a => return op1(a)).then(b => return
| op2(b)).then(c => console.log(c); const a =
| await hello(); const b = await op1(a);
| const c = await op2(b); console.log(c)
|
| In Haskell (>>= is pronounced "bind", \a -> is like a =>
| in JS): hello >>= (\a -> op1 a >>= (\b
| -> op2 b >>= (\c -> show c))) do {
| a <- hello; b <- op1 a; c <- op2
| b; show c }
|
| There is a slight difference, in that JS promises aren't
| monads. But the idea is still here.
| dmitriid wrote:
| > it's just like any other monad
|
| Ah yes. The magic word "just". You "just" do something that
| does something.
|
| And yet even the example in the article uses Promise.then
| and eventual callback hell.
| nsonha wrote:
| I have to admit I don't know much about ReScript and only
| have very basic exposure to OCAML, here is how you do
| await in it:
|
| https://github.com/ocsigen/lwt
|
| The `let* in` is a generic syntax for monads, it doesn't
| need a special one just for promise. This was in fact a
| debate back when async/await was in consideration for
| ECMAScript, but special syntax is hip so now we have
| `async/await` for Promise, `.?` for optionals and
| `flatMap` for arrays, basically the same thing.
| ackfoobar wrote:
| Having seen too much `.map(_.map(` in Scala, I'd argue
| that different words/syntax for different things (that
| happen to have the same algebraic structure) is a good
| thing.
| nsonha wrote:
| yes but they don't have to be keywords or magical syntax,
| can be defined in user land
| dmitriid wrote:
| > here is how you do await in it
|
| That's how you do "await" in a third-party library that
| brings with it a lot of other baggage.
|
| _And_ I doubt it works in ReScript.
|
| > The `let* in` is a generic syntax for monads
|
| Ah yes. "Just" putting `let*` there magically makes
| promises work, is that what you're saying?
|
| It turns out Lwt gained support for let* sytax only in
| April 2020. Stupid them. They didn't know they _just_ had
| to use it.
| ackfoobar wrote:
| > It turns out Lwt gained support for let* sytax only in
| April 2020.
|
| I don't understand your point. Monadic let can be done
| with ppx_let (created in 2016), and even before that
| there was the older syntax where you write `lwt` instead
| of `let`.
|
| https://github.com/ocsigen/lwt/commit/d282049846460426765
| 70d...
| dmitriid wrote:
| > I don't understand your point.
|
| How it started: "In OCAML it's just like any other monad
| you use the bind operator instead. No need for special
| keywords."
|
| How it's going: "well, there's a third party libary that
| only recently introduced let*, but before that you had to
| use either ppx_let [whatever that is -- d.] or an older
| where you use lwt"
|
| You listed no less than three special keywords. And one
| of them specifically introduces a new syntax via ppx.
|
| "Just".
|
| I find this overuse of the word "just" extremely
| infuriating. And FP-community is _especially_ guilty of
| overusing it. "Oh, no need for X, just use <some string
| of smart-sounding words that is always extremely
| convoluted, doesn't actually do what X does, comes with
| caveats the length of the equator etc.>"
| nsonha wrote:
| the point is not that there should be no special syntax,
| but that special syntax in these (functional) languages
| serves a more generic purpose, and isn't just for async.
|
| Ocaml is actually the worst example because it has always
| relied on extensions to provide an alternative to
| Haskell's do notation.
|
| > well, there's a third party library that only recently
| introduced let*
|
| it won't change how you feel about it but `let*` is an
| syntax extension (ppx), kinda like babel transform. It
| has nothing to do with the third party library. What the
| library provide are async primitives, equivalent of the
| `q` package in nodejs
| onox wrote:
| I've been using ReScript for a few months now. So far I mostly
| like it, but it takes some time to get used to it. The error
| messages can be confusing though so I try not to depend too much
| on type inference. The other downside is that some bindings for
| some of the web apis seem to be missing (like for the types in
| the Dom module).
|
| Btw, for Material UI there are already bindings [1]
|
| [1] https://github.com/cca-io/rescript-material-ui
| PUSH_AX wrote:
| > The error messages can be confusing though
|
| I mean TS has that problem too anyway. They're terrible.
| jatins wrote:
| In my experience with these typed alternatives to JS, as long as
| you stay within that language things are good and smooth. But as
| soon as you need to interface with 3rd part lib, that's when
| things start to get messy.
|
| Providing type declarations for every third party lib you might
| want to use, especially in an ecosystem like Javascript's which
| relies heavily on them, gets tiring pretty fast.
|
| Typescript manages to get past that because it has reached a
| level of adoption now that most popular libraries will have a
| @types/<lib> package also but it took a long while to reach that
| stage.
|
| Curious if anyone has used ReScript at a larger scale (and does
| not have the resources of, say, Facebook) and what's their
| experience been like.
| thegreatpeter wrote:
| We use ReScript at Draftbit (https://draftbit.com). We're a
| small company with about 13 people.
|
| Former coworkers have messaged me saying that they miss writing
| ReScript and wish they could convince their team.
|
| We have about 1200 ReScript files on both front-end/back-end.
| It's great. It feels much safer to refactor and write new code.
|
| We use TypeScript in some places, like TypeORM and we're able
| to consume those types on the Rescript side. Rescript generates
| and consumes typescript types via gentype.
|
| I'd strongly recommend you try it!
| greyblake wrote:
| I agree, ReScript has no big adoption (hopefully yet), and
| that's the biggest disadvantage in comparison with TypeScript.
| But somebody has to do the first steps...
| cies wrote:
| There's some project to get TS type annotations to work for
| ReScript. It'd be great if ReScript could lift on the work
| done by the TS community to produce types for many common JS
| libs.
| jatins wrote:
| I wonder how would that work. Typescript has pretty
| advanced types like Template Literal Types[0]. Wouldn't
| ReScript need to support all those types? Or maybe it just
| resorts to `any` equivalent if I can't map a TS type to
| ReScript type.
|
| [0]
| https://www.typescriptlang.org/docs/handbook/2/template-
| lite...
| brundolf wrote:
| One solution is for the language to batteries-include all the
| most important stuff. This is pretty much what Elm does, and it
| seems like ReScript does at least some of that with the React
| integration
| idontwantthis wrote:
| Typescript is great because without it, you still need to
| determine a library's types. It's just that the type checking
| is only done in your head.
|
| If you need to add types to a JS library that still doesn't
| have them for some reason, you're actually doing less work than
| if you didn't add them.
|
| Add the types as needed and you're good.
| elcapitan wrote:
| Is ReScript the same as ReasonML, and is it gaining real traction
| this time?
|
| A couple of years ago I looked into Reason and really liked it,
| but the toolchain wasn't going anywhere and it didn't see a lot
| of adaption back then.
| cies wrote:
| Such a pity they've become two projects. To have on lang for
| both BE and FE is really nice.
| omniscient_oce wrote:
| Honestly that was the selling point of ReasonML to me. Share
| business domain types and share common code but also get a
| native compiled backend. The pattern matching, variants, and
| syntax of Rescript are quite nice but unfortunately I don't
| find it enough of a selling point for frontend code that (in
| my experience) does not benefit as much from those previous
| points as say writing compilers or parsers because the
| majority of what youre writing is interacting with 3rd party
| libs and components, building forms etc in React, for which
| the code ends up looking pretty similar in rescript-react.
| pbiggar wrote:
| We tried doing this with darklang. It ended up not actually
| working that well (it took a lot of effort to have even a
| few shared types), and it didn't get us very much either.
| cies wrote:
| Exactly. I could take the whole "generate API consumer
| client lib from API specification" out of the equation.
| elcapitan wrote:
| Well technically I guess you could still have that via node,
| just not native as with the Ocaml compiler?
| askonomm wrote:
| And via Deno as well.
| cies wrote:
| I rather work with OCaml/httpaf[0] than with JS/express or
| what have you.
|
| [0]: https://github.com/inhabitedtype/httpaf
| ronenlh wrote:
| Yes and no. The syntax has been updated to make it less OCaml
| and more JavaScript-like.
|
| ReasonML can compile to native, rescript can't. Reason still
| exists as a separate project, and projects that have been
| rewritten into reason will not necessarily switch.
| pbiggar wrote:
| In theory this is correct, but in practice Reason(ML) is
| dead. Or it was the last time I checked a month or two ago.
|
| ReScript lives on though.
___________________________________________________________________
(page generated 2022-01-12 23:02 UTC)