6 ms·
Show HN: ESInfer – Make JavaScript Type-Safe
Hello, folks. I'm Jiang, the author of ESInfer.
I love writing Javascript because it has a prosperous ecosystem and is quick to get my hands dirty. However, sometimes it's painful when the flow is not fast to follow due to the lack of a type system.
To solve this, I wrote ESInfer, a statical inference tool, to automatically type check and generate type annotations for Javascript.
It works with pure Javascript without any add-ons to the language or user-space code and supports highly dynamic features, such as the modification of prototypes.
It is still in the very early stage, which offers almost all ES5 features and a select set of ES6 features like array/object destructing. I'm working hard to bring all ES6+ features into it incrementally.
If you heavily use javascript/typescript and do NOT want to write the type annotation sh*ts anymore, give it a try :)
- deleted 4y ago[deleted]
- activitypea 4y agoThis looks really interesting! How is it different from just running flowtype over plain js?
- jiangmy 4y agoThe difficulty comes from how dynamic language features you support & how accurate the type is inferred. Both in typescript and flow, you need to write annotations/comments to help the compiler perform well. ESInfer is doing it all statically and without additional stuff needed. You can try it out on the playground section at the bottom of the homepage. Would be glad if there is any feedback :)
- activitypea 4y ago> Both in typescript and flow, you need to write annotations to help the compiler perform well. For Flow, that's true only in the most literal sense. Flow has excellent inference and can get a lot done without the user writing any annotations.
- ipsum2 4y ago> you need to write annotations/comments to help the compiler perform well. That's not true of either AFAIK. Annotations help, but it can still catch things without them like: function x() { return "x"; } x() - 15; // Cannot perform arithmetic operation because string [1] is not a number.
- wolfgang42 4y agoThe website seems like it needs an explanation of what this is for and when you’d want to use it; right now it leaves quite a lot to the imagination. (Also, the GitHub link in the corner (a) requires JavaScript for some reason instead of just being a normal link, and (b) goes to an empty repo so it doesn’t seem to be possible to use this thing.) A big part of my confusion, I think, is that I’m not sure why you’d want to write code without type annotations. I can see a use for autogenerating them from code that doesn’t have any, but the first example on the page infers the return type of hello() as “t547061|string” which is rather more opaque than I’d prefer from a diagnostic. A big part of why I use TypeScript is because of the type annotations: both so future readers can understand my intent, and also to give the type checker hints about what I was thinking so it can point to exactly where I went wrong instead of going “this over here doesn’t work with that thing over there, I dunno, there’s probably something in the middle that’s not right.” So I’m curious what your thoughts are on why you dislike annotations and how to make type errors clear without leaning on them for support.
- pyrolistical 4y agoI think this would be useful for writing rules for eslint. For example, let's say we want to ensure object types don't change for their entire lifecycle. const foo = { answer: 42 } // change values but not type is OK foo.answer = 69; // creating a new object is OK const bar = { baz: foo } // disallow adding/removing fields, IE changing type // ERROR, expected type of foo to be {answer: number}, unexpected field reply: string foo.reply = "nice";
- jiangmy 4y agoThanks for your reply, and sorry for the confusion! 1. I replaced the GitHub link with a direct link now. Because it is still in the very early stage, the repo is only open for discussions like feature requests, using feedback, etc. 2. The main point is to do type check & annotation generation all automatically without one single line of additional code needed, which both flow nor typescript cannot achieve at present. 3. I'd like annotations to tip me on the type and to let the editor give me code suggestions based on them; however, I do not want to write them manually. 4. As for how to get type errors clear enough without learning, I'm doing it by avoiding using PL/type-system-related terms during the entire process. For example, `let a = 1; a = '1';` will raise an error that says `expecting number but got string.` to tell the user with easy to understand the sentence. For more complicated situations, like overloading mismatch, please experiment by the playground at the bottom of the homepage. (very sorry, I do not know how to write markdown on HN). Any feedback or thoughts on that is very welcome! 5. For the inferring result like `t547061|string` you pointed out. Yes, I agree that it's annoying. I will simplify the outcomes for the sake of readability over strictly correctness. But the top priority is still to add more ES6+ features if I think correctly. Thank you again for the detailed feedback, and I apologize for any unclear caused. It's still early, and feedback like this is more than welcome. Thank you!
- LASR 4y agoSo this is a way to generate type annotations for you from JS? The application must be to generate typescript as an example? I would encourage you to add some reasoning to your site.
- jiangmy 4y agoYes, I did not do the paperwork well enough. I'm writing more articles and adding more examples on the website in the following days. As a brief reply here, it provides the ability to do statical type inference for javascript without writing additional code. With this ability, libraries or editors can perform better on code assistant/suggestion, linting, statical analysis, annotation generation for or not for typescript/flow, and so on.
- sergiomattei 4y agoI don’t know. To me, the biggest benefit of TypeScript is dumping all the types on my brain onto the screen. It’s easier to maintain in the future, when I don’t have to do so many mental gymnastics to understand the data behind my code.
- redact207 4y agoSecond this. Also much easier to pick up code or review a PR if the types are explicitly provided rather having to backtrack to see how something's called.
- deleted 4y ago[deleted]
- jiangmy 4y agoThank you for clarifying and providing the use case. It makes total sense to me! I'm adding this to my to-do list. There can be many potential use cases, such as providing typing information to the IDE's LSP, ejecting them directly to the code as you suggested, integrating them into the CI process, etc. I'm very open to providing all those possibilities, and there's no reason to limit how you use the typing information when you possess them automatically.
- brundolf 4y agoYou shouldn't need mental gymnastics, you should be able to just hover the values in your editor There are other reasons to use explicit types part of the time- but they don't really have to do with readability
- wildrhythms 4y agoThis isn't so easy when you're trying to parse a hundreds-line function written by god knows who that has many early returns each returning an object with wildly different properties. Declaring the return type the method declaration is valuable.
- cercatrova 4y agoHow does this compare to Ezno? It evaluates types dependently even, so that something like `const x: 5 = 4 + 2` creates a compile time error, as it knows x equals 6, not 5 like its type states. https://kaleidawave.github.io/posts/introducing-ezno/ https://kaleidawave.github.io/posts/introducing-ezno/ https://news.ycombinator.com/item?id=32941613 https://news.ycombinator.com/item?id=32941613
- jiangmy 4y agoThank you for sharing that great work! It's more like a dependent-type plug-in to typescript to me, if I understand it correctly. ESInfer and Ezno work on different layers, in my opinion. ESInfer provides a general ability to type-check code, yet Ezno improves a type system by adding the dependent type support. Ezno can work on top of typescript and could work with ESInfer, right? An easy way to do this is to use ESInfer to generate typescript annotations and then pass it to Ezno.
- cercatrova 4y agoActually Ezno wants to do what you're saying as well, the general ability to type-check code, not just add dependent types on top. Their website has some more examples. See also, Hegel, which also wants to statically type check JS without TS necessarily. Looks like this space is heating up! https://hegel.js.org/ https://hegel.js.org/ https://news.ycombinator.com/item?id=33162275 https://news.ycombinator.com/item?id=33162275
- jiangmy 4y agoHype up, Dude! Very glad to see so many afford to make javascript a better language there! I played it around, and I found Hegel seems not to support dynamic features like modifications of objects or prototypes. And this is the real difficulty of implementing a sound and complete type system to a dynamic script language like javascript. Can you share if they have any plans for that? https://hegel.js.org/try#GYVwdgxgLglg9mABFApgZygCgIYEpEDeAUIqcgBYxoB02iAvItgNwlkBOKUI7SAjKwC+RIhAQYmDRGBQB3ZOiwAmXKyKoM1AA7s4UPQE8tKagCMpAcj4W1YsBIhTsZ5kA https://hegel.js.org/try#GYVwdgxgLglg9mABFApgZygCgIYEpEDeAUI... https://hegel.js.org/try#MYewdgzgLgBCMF4YG8CGAuFAjTBGAvvgNwBQJIAdACaIoYwDkATA8WaJLDUpVaR9BipavCqiJA https://hegel.js.org/try#MYewdgzgLgBCMF4YG8CGAuFAjTBGAvvgNwB...
- dalmo3 4y agoI'm not sure I understand the use case for this, but I had a go in the playground let a = [3] a = [''] // this works? a[0].length // but this fails? Error message is > expecting possible candidates all failed: candidate array failed: expecting number but got string. candidate object failed: missing field 'length' but got number.
- jiangmy 4y agoGood One! There are two issues here: 1. Tuple or Array? The inferred type will be different depending on that decision. Currently, I go for the Array one, so if you remove the `a[0].length` line, you will see `a` be inferred as `[string|number]`. But this will change if I think about this more thoroughly. What are your thoughts? 2. const/let constrain, constexpr, `if guarding,` and some internal methods are not implemented yet, so this is a false negative. But indeed will do!
- WirelessGigabit 4y agoType annotation is not shit. It’s a contract. What’s the point of you discovering the return type is a string. If I write a function and I set the return type to string and return a number it blows up on my face. With a deduction that’s not the case.
- danielEM 4y agoYou're missing a key point here, this is JavaScript, so there is no type annotations. And even if there were and inference was available as well then in most of cases I don't think you would need to annotate a type of function, as at some point it would 'blow up your face' anyway when mismatch of types.
- WirelessGigabit 4y ago// bar.foo is number // getFoo() returns a number bar.foo += getFoo(); // getFoo() has a bug and now returns a string. Nothing fails. If getFoo() had a return type of number this wouldn’t be the case.
- IshKebab 4y agoJavaScript has type annotations, they're called Typescript. And this doesn't seem to be sold as an automated way to convert JS code to TS (which would be really useful). It seems like they intend for you to stick to pure JS code which makes no sense really. > at some point it would 'blow up your face' anyway I'm not sure exactly what you're saying but yes you do need to annotate the types of functions. Global type inference is possible but it has performance issues, makes type errors way harder to debug and obscures the intent of code. Types are a part of your interface. They should be stated, not inferred. I would rather things didn't blow my face up.
- Spivak 4y agoOdd, I feel wildly different about the “point” of types. For me, in cases where the type checker correctly infers the type saves me work. If I depend on the return type of my function being string and I change it the type checker will complain at the call site making the annotation pointless. If I don’t depend on it anywhere I can safely change it again making the annotation pointless. For me the type checker exists to help me understand relationships and integration points, any time spent fucking with the types for its own sake is a waste. If I find a situation where updating the code would require I update the types I’ve just written the same thing twice for some reason. I want the type checker to tell me when things are genuinely bugs in my code because of incompatible types not because it doesn’t match the annotation. Even in libraries where I can’t see all the callsites all my promises to the caller are encoded in the tests which to me is a stronger guarantee and the type checker will still catch it just over there.
- throwaway675309 4y agoI'm sorry, but I've gone through your site about a dozen times and I have absolutely no idea what this does. Is it a post-processor that appends jsdoc annotations? Is it a vs code plugin that constantly checks your js for type issues? Is it a dedicated lint type tool that you run via npm? How is this different than jsdoc with a smart ide, or better still typescript? Best of luck, but you really need to add a FAQ.
- skaushik92 4y agoI agree; I appreciated the visualization of the Infer button but its not clear at all if this one of the options you indicated. What I found though is that this is likely at least partially service-based. The UI's infer button seems to make an API call to the site's /infer route, which then returns the decorations that need to be shown for a specific line/column. This seems like the wrong direction IMHO because it relies on a backend that gets access to full source-code. On the other hand, if this is supposed to be a self-hosted endpoint, that may change my opinion, but that doesn't seem to be clarified on the website at all, which is rather suspicious IMO.
- theogravity 4y agoOutside of using it with a large codebase that was written in vanilla JS, I can't see a reason why I would use this over Typescript. Maybe it should have the additional functionality of converting vanilla JS to Typescript as the main selling point.
- zupa-hu 4y agoAre you sure you are solving a real problem? Seems to me you must be really smart and found a cool idea to work on. If that’s your hobby, cool. If you want others to use it, make sure you nail the problem you are solving and that it resonates with enough people. I’d like to also vote that typescript is strictly better. Relative to TS, your solution increases uncertainity and makes code documentation worse. What’s the gain?
- still_grokking 4y agoHow does it work? What does this mean: let hmm:t5034175 = ([] == {}); let mmh:t5034194 = ({} == []); var r:string = null; if (hmm) { r = hmm; } else { r = mmh; } r = hmm + mmh; :(possible candidates all failed: ) -> possible candidates all failed: function f (t) { return t + t; } :possible candidates all failed: var rrr = f(r); ?
- jiangmy 4y agoThanks for the bug reporting. I have deployed a new version on the server to get this fixed!
- still_grokking 4y agoBug reporting? I was only playing around, not understanding what this thingy is actually doing. :-) I still don't know as you didn't explain anything. Is there maybe a paper or something I could read?
- jiangmy 4y agoThank you all for sharing constructive thoughts and concerns. I have written more FAQs on the website to make it more clear that what you can do with ESInfer. Plus, a `Comparison to Typescript` thread on the discussions repo on Github. https://github.com/ESInfer/discus/discussions/1 https://github.com/ESInfer/discus/discussions/1 And I'm planning to write more articles shortly.