First look: adding type annotations to JavaScript
2ality.com
2ality.com
Forking projects just to add type definitions, or else mega repos like DefinitelyTyped madness; bringing all of the terrible complexity that we love to hate in Webpack/ESBuild/Rollup/etc back over to Node.js with server-side tsc; drive-by PRs to all my open source projects from inspired people trying to add types and me having to disappoint...
I would gladly do without all of that. To me, I see the TypeScript tradeoff as coming with only marginal upside, in return for a large downside as described above. But, others passionately disagree and see a huge upside, and that's cool.
In the end, I want us all to be happy, and I think this proposal would have hope getting us there. For this to be really spec'd and standardized would be a green light even for skeptics to invest in deeply learning and internalizing. To get to avoid yet another build-time compilation step would be bliss. To have us all back in on the same team would be glorious.
Having said that, it might be because when I'm writing JavaScript it's just me. Normally I'm the sole developer. So of course I know my own stuff! I'm not going to experience an error passing the wrong type to a function because I literally wrote all the functions myself. I even have enormous libraries of JS code that I use in my personal and work projects where I wrote everything.
This developer is probably in the same sort of situation. Type errors are the kind of thing you run into when you're working with large codebases that were written by lots of different people. It's not the type of thing you experience with your own code.
I've also written loads of Python and never experienced an error where the wrong type gets passed to a function (even working in a team). For years I couldn't even fathom how static typing would be a benefit other than maybe it can speed things up by giving a compiler/interpreter the ability to optimize things. Then at work--after nearly 20 years of Python--we finally had an issue where the wrong type was passed (float was inadvertently rounded because the function was made for integers and it wasn't obvious). It was caught before the code was sent to production (and it wouldn't have been a huge deal anyway) and I finally had a real-world situation where type annotations would've prevented an error.
It's just not something that happens very often. It's the type of thing that creeps up on you for sure but it's not a common, every day occurrence. Type-related bugs are really super obscure. They're far, far rarer than type-obsessed developers make them out to be.
If you don't validate that all untrusted data is off the appropriate type, security vulns or "garbage in - garbage out" bugs can result.
Then if you do manually validate the types of untrusted data, then you have to wonder of having built-in type support might be faster.
"Bad data" doesn't just come from the outside world. As teams start to use shared libraries written by other people, it's also valuable adds guards to ensure that shared functions are being called with the expected types.
My own experience is that it doesn't feel like type-related bugs come up often on my team, but when they do the problems they cause can be bad enough to make us wish more of our code had been ported to TypeScript.
Classic example: a CSV parser parsed numbers as strings because a particular spreadsheet quoted the number column. Result: "2"+"2" = "22"
Yeah, they're optional, but if you don't write them, there's no point in using TypeScript in the first place.
2) If the types can be inferred, that should just happen. No objection there. But this piece is specifically about "adding (manually-authored) type annotations to JavaScript"
Or just to the developer that likes to offload that cognitive load to their tools.
Why hold that in my head when the IDE can keep track of it for me? Why memorize every single attribute name when the IDE can autocomplete it for me? etc.
Instead keeping track of the type annotation in your head, and then also keeping track of the rest of the stuff in your head too.
Quite the claim! For me the moment I never want to look back to is to refactor a substantial part of the architecture of a JS app with more than 20k lines of code (And I did write most of it myself). If you don't do large scale refactorings or work mostly on smaller apps, then indeed, types won't be much of an issue.
But you should become aware about how often you see "undefined is not an object" and similar, that's a type error that is almost gone when using TypeScript.
Maybe you just see the "cannot find property of undefined" type of errors as usual business, but this is the #1 kind of error I see in the logs of big applications, and TypeScript really helps to mitigate them.
When refactoring is easier, it happens more often, which means code quality and readability are higher, which reduces the likelihood of every other kind of error.
You absolutely have. At some point in your career, you've accidentally got the arguments to a function in the wrong order and had to debug what was happening. Or ended up with a `null` where you didn't expect it. Or used an invalid value for a string enumeration, made an inobvious typo in a field name of an options object, accidentally added brackets and called a function when you meant to pass a reference to it, failed to deal with the return type of a promise, or any number of other examples of mistakes that everybody makes all of the time.
These are all examples of common errors that can be caught by a type checker. It's totally valid to debate whether the cost of a type system is worth paying in the context of different environments, but if you're starting from the not-really-credible position of "I have never made a type error, ever", then it suggests that you're working with a set of faulty assumptions about what they offer.
(For my own part, as a Javascript user of some 20+ years now, picking up TypeScript has been the best boost to productivity and code quality I've had in my career. It's got to the point that I'd just point-blank refuse to work with a Javascript codebase now, because it's not worth it.)
I have to say I'm a convert. Not so much because it's catching a ton of errors for me, more that it brings such a massive improvement in IDE autocomplete behaviour. TypeScript in VS Code starts to feel almost like C# in 'real' visual studio. (The errors it does catch in my code are usually potential null references which would probably have been fine, but I'm sure it's avoided a few bugs.)
The most interesting thing for me is that it allows me to feel safe doing things I would avoid in plain JS, like using literal union types (which would be magic numbers/strings without the typing).
I still write JS for small stuff, but when you're next starting a new project that'll go over a few thousand lines of code I definitely recommend giving it a try.
Inline /* @type */ statements and jsdoc type declarations coupled with .d.ts files for complex types achieves the same thing for me without the extra compilation step.
const myFunction(a: Long<TypeName>, b: Another<LongType>): FooBarOkay, well, here's an example of it leading to a CVE: https://www.mozilla.org/en-US/security/advisories/mfsa2012-7...
The way-and-how of it is that the then-new devtools team working on the then-new JS console lost track of what objects they were passing into a polymorphic function, which resulted in untrusted, content-supplied objects being treated the same as DOM nodes that were supposed to originate from within the JS console implementation itself (for its UI), which resulted in browser-level privileges being given to content authors of ordinary web pages.
Well, you don't need types because you only look at your own code. The advantage of having my IDE tell me what to expect when I'm refactoring a piece of code someone else wrote is a few orders of magnitude more useful and informative than having to jump through various functions and files to understand what's happening.
Years of writing code do not equate to proficiency and expertise. You may have been writing code for many years but I would go so far as to assume that you experience is actually very limited.
I do agree it would be nice to simplify some of the tooling though.
I feel like I was crippling myself for years, being an inferior developer wasting so much time with the things that TS guards against, documents, and autocompletes for.
I support any formalization of TypeScript that further tidies up the "add-on" nature of it. But to be honest, it's really quite fine already.
For example, I once was debugging an issue in a JS framework and while I knew what was wrong and where I could fix it I didn’t have any idea what existing tools I had available in that context to fix it. Having type definitions would have made that work much simpler by increasing the accessibility of the code base.
It’s experiences like this that have convinced me that if I’m writing code that any one will possibly read or need to modify later (including if it is just me) then I should be writing TypeScript instead of JavaScript. Or, more generally, that it should be typed.
At the scale I operate, it would be corporate suicide to try and write this code in straight JavaScript without type support. But for smaller teams, more focused teams, and teams that use a heavy testing discipline or enforced naming conventions that supplement the lack of static typing, it's not a problem.
Everytime there is an any, it means that each developer reading or modifying this code has to find it out for themselves - every single time. Why not just type hint it correctly in the first place.
Anyways, it's TS, and I don't know TS but I know how typing works so I can make my way around. I need to alter an interface to fix the bug, but with all the code it's very difficult to tell whether the change will break something either in the compiler or at runtime. To add on top of all that, the client needed the change to go out that day.
So guess what's going to happen? I'm using fucking `any` and I don't care.
Ultimately, this is why I don't like TS. I think it's a great idea, but if you look at all the energy that has been spent moving code over to TS from JS, and all the type definitions that were written into existing NPM packages, I have to ask myself why we don't just pursue making types native to JS? I don't want to write a secondary language that compiles to JS.
It is massively easier to make change to large TS codebase. Just because you never bothered to learn TS and you rush feature at cost to maintenance, do not mean it is TS fault.
> Ultimately, this is why I don't like TS. I think it's a great idea, but if you look at all the energy that has been spent moving code over to TS from JS, and all the type definitions that were written into existing NPM packages, I have to ask myself why we don't just pursue making types native to JS? I don't want to write a secondary language that compiles to JS.
Because native types would create even more fragmentation while being less powerful than TS. JS was never intended for application development, we either embrace compilers or move away from language that have pathetic standard library, dynamic and complex type coercion rules, no stable module system, lack of strong leadership and legacy of supporting IE.
https://github.com/typescript-eslint/typescript-eslint/blob/...
So while you technically are disagreeing with the parent, it's on the smallest of points, and completely disregarding the main one the parent offered (which, fair enough, but wanted to point that out)
Those issues aren't due to tsc. They're due to an ecosystem which refuses to recognize the realities of compilation and add first class support for it. Its also due to an ecosystem willing to break compatibility (and not just backward compatibility but compatibility to other tools) at the drop of a hat.
For example, the main reason I've seen why people began using bundlers for node recently is the fact that a lot of modules transitioned to pure ES6 without CommonJS support. In most projects, this means you have to use a bundler to be able to import those modules, or switch your entire codebase to ES6 (which is non-trivial due to changes in import path semantics).
If it weren't for the above, you could just run `tsc` to get a `.js` file in `dist` for every `.ts.` file in `src` and run node on those.
IMO this is the correct path. Compilation should result in WebAssembly and it seems like the tooling is finally getting there.
It... It really shouldn't. Especially not if the target is the browser as the bridge between WebAssembly and the rest of the browser is still "just pass these arrays of integers around".
- what about tests, how do they run
- source maps support in node being 3rd party and unbearably slow for any medium sized project
- edit: this has been fixed somewhat recently https://nodejs.medium.com/source-maps-in-node-js-482872b56116
- only the 3rd party bit, not the slowness bit https://github.com/nodejs/node/issues/41541
- also applicable when not bundling, albiet fewer reprcutions to turning off source maps
- poor native (C++) modules support in bundlers
- modules with really dynamic `require` statements being supported at varying levels by varying bundlersThe real lightbulb moment for me was using JSDoc annotations with TypeScript types in JS files. It definitely isn’t as graceful as JS itself but it’s not that big of a deal, plus it encourages you to add comments. And any TypeScript editor will parse the code as if it’s TS, provide autocomplete, type checking etc etc as required.
stuff.anAccountTypeField = obj.aNumberValue;
Would cause an error in a typed language , something like incompatible type Number and type Account.
Maybe you were confused by my commnet about the network requests and different order of running code, this caused the error not to happen most of the time so it never crashed on developer machine.
I've coded using static and dynamic types. C#, Java, Ruby, JS, etc. 20 something years doing it, mainly for business applications (opposed to system or embedded). My personal opinion is that types bring an elusive value of control and maintainability. Confronted with legacy / spaghetti code, developers with less experience will bring lint, code style, some layers and ... types, as a way to solve the problem of long term maintainability.
But unfortunately it does not bring that much value. Actually it brings costs to readability and unnecessary abstraction (interfaces, generics, etc) aka "fighting the compiler".
A better test suite can have exponential more value on maintainability than types.
> Static Typing was the most requested language feature in the State of JS survey in both 2020 and 2021. [1]
So when I see static types been the most requested feature I wonder how many of them know how to create a good test suit or a good architecture. If its behind this feature request is a different pain to be solved.
[1] https://github.com/giltayar/proposal-types-as-comments/#comm...
A lot of ink has been spilled over this question. The conclusion is: no, tests do not and cannot replace types. Types, in themselves, provide a layer of tests that nobody, typically, would think of writing (what if a function is called with fewer arguments? what if it receives a different type of argument from what it was expecting?) and eliminate a whole class of superfluous tests that are checking for things that are better checked with types.
The self-documenting property of types is remarkable. Jsdocs do not hold a candle to a typed codebase.
Plus, refactoring. Even with tests I would be scared of large refactorings if I didn't have a type checker to also hold my hand. Of course, maybe I just don't know how to write code properly.
Can interfaces be confusing, and generics become difficult to read? Yeah of course, but that's not really the problem of static type system, that's a problem with the code. I've generally found if you're doing something where you're thinking "this is just getting the way", you probably need to rethink your approach. Clear is always better than clever.
I would say exactly the opposite - beginners pick languages without [much] typing because it is or at least it seems easier to get started. When you step out of toy program territory you will start to appreciate the value of types.
It's hard to tell whether the reason beginners pick languages is because they are not typed or because they are immediately practical (such as javascript, php or python). Christopher Allen's and Julie Moronuki's Haskell Programming from First Principles is targeted at complete beginners. Harvard's CS50, which starts with C (well, Scratch, technically; then C), also targets beginners.
You don't see much lisp among beginners, despite the absence of type notation.
No, it is not hard to tell. Programming beginners positively do not choose languages by evaluating concepts that they have no clue about.
> You don't see much lisp among beginners, despite the absence of type notation.
Lisps are simply not widely promoted to beginners; there aren't enough people to do that.
Beginners end up learning whatever is thrust at them most frequently and loudly. Basically, the non-beginners more or less decide that for the beginners.
Machine-verifiable documentation about the intended I/O of functions and shapes of structs and objects is hugely fucking valuable to everyone. Your documentation isn't good enough if it doesn't include that, so it may as well be in a format that a machine can read, validate, and use to help out every single person who ever has to read or touch that code.
Types catch a lot of stupid errors that anyone can make, regardless of skill level.
They also localize guarantees. If your data has a type, you don't need to understand the full path it took to arrive in your function to be able to work with it. With dynamic types, you can only hope that a value has the type you need unless you explicitly check every time.
I've been using Elm for the last 2 years and it's not that I don't fight the compiler, but I constantly use it to guide me while refactoring. Elm code is extremely readable and types (including Maybe, Result, etc.) just give so much confidence and control to the programmer. While working with an Elm code base, refactoring is a constant, joyful, safe act.
It is true that in many cases good tests help. However often when I work with Python (using type hints), I need to write a unit test just to ensure a contract that I could explicity state using types in Elm. It doesn't feel right.
In general dynamic types incentivize the status quo and promote codebase ossification, and somewhat ironically make rapid prototyping harder.
> But unfortunately it does not bring that much value.
If you mean adding these things post-hoc, yes the value is limited. If you start with types, and you embrace them as a design and testing tool, they can literally change the kind of code you write in the first place.
People talk about how convoluted TS types are, but the reality is that’s because they’re describing convoluted JS. TS-first code tends to be a great deal more straightforward, because you define the interface before implementing it.
In other words, if you start out with static types and think about them first, you’ve likely already got a good architecture and test suite.
I kid... mostly. But in all honesty I have found very few instances of developers who have worked significantly with both languages and have come to the conclusion that TS has a marginal upside (though maybe they will come out in defense here!).
I've worked extensively with both.
I find that ts normally brings a downside, actually. In one project I maintain, a solid 30% of the code is nothing but ts stuff.
It makes maintaining the code base excruciating.
Small changes between versions of ts or .d.ts files have caused hundreds of errors. A concrete example of this is the change in mongo driver that forced "new ObjectId()" instead of "ObjectId()" though functionally there was no difference.
I see massive bizarre and difficult to grok type declarations that grow in excruciatingly byzantine complexity just to satisfy the compiler for non-trivial flexible function definitions.
I see painful compilation times, a beefy laptop's CPU getting pegged and the fan whining while trying to do even minor updates.
Try to do a build while on a video conference? I see two to three minute build times.
I see a series of nonsense stories in sprints that are nothing more than activity over achievement. They don't drive product functionality, they are a bunch of make-work to satisfy the developer asthetic and the compiler.
The nightmare of "compiled" NodeJS production support is a dystopian hellscape that I'm forced to endure every day because of NestJS and typescript. And nothing in that has done anything to increase code quality or reduce bugs from the crappy offshore team that wrote it.
Clearly, I'm not a fan.
That being said, I think type comments in jsdoc are a honking good idea.
I use inline /* @type */ declarations and .d.ts files liberally.
If we could add to jsdoc the ability to document types and purpose of arbitrary js objects inline, at definition time, instead of an external .d.ts file, I'd be a happy guy.
An example of this would be sequelize schema defs, or mongoose schema defs, where I can have all my jsdoc code comments and type definitions in the same place as the code.
All that being said, I like the idea of this proposal. Especially if it could solve the schema definition issue above.
I think optional typing is a good idea to bake directly into the language. I thought AS3 did a great job of this.
I even think it would be great to have an equivalent of "strict" that would enforce typing at the module level to enable straightforward AOT / wasm interop (I know it doesn't solve the GC issue).
My beef is mostly with the extra compilation step and needless complexity of ts.
If we had simple (no generics) opt-in typing that was natively supported by the engine, I think it would enhance the language overall, like type hints have done for python.
Is this better or worse than no type definition? Whether or not a type is defined it is still consumed. I can totally understand that sometimes types can get a bit unwieldy, but those are the exact scenarios that save future-you from introducing a bug because you didn't know what a variable is (and is not). At the very least it may be an indicator of poor design/code smell when the above occurs.
I hear you on compilation/build process woes. That's the fairest criticism against TypeScript IMO (though it's a fairly weak argument as well).
Most of your other critiques aren't really levied against TypeScript, rather, your work environment (not that it makes working with TS any less painful!).
Things with optional parameters that can accept a wide variety of types, async callbacks and async variadic return types.
The hoops you need to jump through to make the compiler happy are absurd.
Could be avoided by having more functions, one for each case.
(Only if you control the code, of course.)
I have no doubt that a sizable portion of these functions' bodies is dedicated to figuring out which type each of our input variables represent (from our wide variety). So now instead of having our editor/compiler help us out, we are now actually writing code to figure it out ourselves... this is more absurd (and less efficient).
And FWIW, using union types makes it trivial to denote that a function can accept a wide variety of types in a type-safe way. But guess what you will be doing first thing in the function body? Discriminating that union!
That 30% number is almost certainly why. The experience with codebases with 100% type coverage / tight types have been glorious, and the ones with partial coverage / plain js files / lots of "as any" / lack of strict compiler flags https://www.typescriptlang.org/docs/handbook/compiler-option... have been miserable and a waste of time. Can't stress the strict flags enough.
One of the "pros" of typescript is its gradual typing, but I think it's a trap and forces poor impressions on people.
One of those reasons is how `any` works. In gradual adoption, lots of stuff turns into `any`. `any` is a contagious/viral construct where anything it touches could become `any`. And then you spiral out of control and the whole codebase gets nothing from typescript but gets all the operational overhead.
If your browser doesn't support text fragments, can cmd/ctrl+f for "contagious" and/or "gradual" https://www.typescriptlang.org/docs/handbook/typescript-in-5...
30% is a conservative number.
Sounds high but if it's true it's true.
If you want a type system Typescript works great, and it's very easy to set up. You even get debugging to the original uncompiled source with sourcemaps.
If you want a strongly-typed static language, compile to a wasm target... That's what it is for.
Stop trying to change JavaScript into a language it is not.
JMHO
I do not think the demand is quite as huge as you think it is.
Just because a feature is not widely adopted it doesn't mean that is not useful to the people using it, especially when the feature is used to mitigate the entire "cannot find property of undefined" type of errors.
> I can understand if JavaScript developers are afraid of TypeScript taking over their language. However, this proposal will be as far as things will go w.r.t. adding TypeScript features to JavaScript
And in the next few sections it includes someone who wants to build on the proposal including using type hints to optimize code. I just think there's literally no way to guarantee that "this will be as far as things will go". Yes languages evolve and add new things all the time. But GP's point is that the language seems to be going toward what people want it to be coming from other languages.
I agree, stop trying to make JS something it's not.
This changes literally nothing about the JS language. JS engines already attempt to determine the types of things to optimize the code they generate. Type annotations would just allow them to make more aggressive optimizations.
Besides adding a bunch of new syntax, of which JS already has far too much.
But it does mean there likely isn't a "huge demand", which was the original claim.
You're attempting to move the goalposts here.
Most of the changes to JS in the last 20 years, have been serious improvements, but they did not change the fundamental characteristics of the language.
Believe it or not there are a lot of people that like JavaScript!
How dare you use JavaScript for anything else than validating forms!!! What is that jQuery thing??? Stop trying to make JavaScript into something it's not!!!
Is C only used for forms?
EDIT: I never said JS shouldn't evolve! JavaScript has evolved a ton! From better handling of asynchronous control-flow with promises and then async/await, to destructing, spreads, constant assignments, Map/Set objects, a number of other improvements I can't even begin to list. But none of these changes fundamentally changed JavaScript from being a dynamic weakly typed language.
A lot of these "problems" (implicits, enums, etc) were solved with Scala 3 too. Another example of a language evolving and becoming better based on community feedback and thoughtful iteration.
But the reason I never adopted TS is because one time I spent months converting Coffeescript back into JS once it fell out of favor. This was back when a bunch of Ruby developers decided that JS should look like Ruby.
If I'm writing Javascript, I'm writing Javascript, not something that pretends to be something else.
I ran a team that had to maintain a large Coffee codebase, that we could never get the resources to move off. So I know that pain. TS is different, both in how it works and the level of adoption. Coffeescript was always niche, and some benefits were there but they weren’t game-changing for (eg) writing correct code or maintaining large codebases.
FWIW, this proposal does not change the fundamental characteristics of javascript. It just adds a new comment syntax.
Besides, adding even more complexity to the JS ecosystem at this point is like pouring a cup of water into the sea.
// Dog Class
function Dog(_name){
// call the parent constructor
Animal.apply(this,arguments);
}
// extends the Animal prototype chain
Dog.prototype = new Animal();
Although the new class syntax may obfuscate from what's actually happening in an effort to look more like traditional class-based languages like Java.However I'm the type of person that will only use React function components in my codebase. I don't think the object-oriented style has added much too my programming, except the temptation to reach for an unnecessary abstraction.
The same is true of PHP. People hate it. People complain. PHP takes the criticism and makes updates. People complain more.
JavaScript has evolved as an untyped language, it has type-coercion and a single way to represent (most) objects in memory. So regardless of what kind of syntax you add on top... it will still be a untyped dynamic language internally. Are we talking about changing this truth? Or just adding additional syntax for developers?
Since the proposal doesn't care about the semantics of the type annotations, it doesn't even necessitate typescript. It would work just as well with Flow typing or even a completely new type checker.
V8 still has to updater its parser. Other tools that handle JavaScript parsing need to do that as well.
> You'd be able able to use typescript autocomplete and linting in your editor, and just serve the files to your browser with a static http server.
Nope, it's not using TypeScript directly, but just another language very similar to TypeScript.
The counter-argument to that is: everyone minifies code anyway, but this feels like a very poor argument. "Adding cruft is OK because most people have complicated build chains to get rid of it" is very different from "we've opted into a build chain (tsc) and now have access to adding cruft"; there's a default situation here, which is the many people who write JS (FE or BE) and aren't minifying it.
Additionally, their pipe dream of allowing TS to become standard JS "if they stick within a certain reasonably large subset of the language" (an actual quote from the TC) is... wild. Wild. No thoughts, just vibes. Typescript is an extremely mature, fast-moving, complex project. Their list of TS features not supported under this TC is only three items long (with enums and namespaces among the list, lol), but I guarantee there are TONS of very complex type-level assertions typescript is capable of which JS is years, maybe decades, from reaching considering the glacial speed ECMA moves at.
Typescript will always be a superset, which they admit. The problem is: I hold extreme doubt that JS/ECMA is even capable of communicating what that differential is to average users. Will JS support control flow analysis for dependent parameters, aliased conditions, and discriminants? Const assertions? Middle rest elements in tuples?
Typescript adds all these assertions, and more, every couple months, because it turns out that type systems are something of a pandora's box. Few language-level type systems remain at the simplicity of, say, Go; most become TS, or Rust, or Java. That's not a bad thing, but not everything should be that.
If this gets traction and built, JS will in-effect, though not in-requirement, turn from an interpreted language to a compiled language, whose compiler isn't even maintained by the core development teams. That's a major, major shift; and I'm not sure the proposers have even considered the ramifications of it.
The fact that they by design have no impact on the runtime isn't really even a positive. That could be a large tactile benefit of this RFC; that suddenly JS is capable of communicating to its runtime what types different primitives are, such that the runtime can optimize their storage and usage. But, by design, they don't want this. Maybe that could change in the future, but I suspect it won't because the proposers have taken the stance that everyone minifies anyway so the syntax doesn't matter anymore.
[0] - https://github.com/microsoft/TypeScript/wiki/Roadmap#future
---
const user: User = {
...
};---
Why couldn't this be more like C rather than this weird conflation with the existing colon token?
---
const User user = {
...
};---
That might seem not as pleasing to those familiar with Typescript, but it's much closer to other existing syntaxes (meaning less of a learning curve coming from Java or C).
Same with function definitions:
---
function foo (bar: string, baz: boolean): Qux {
...
}---
Versus:
---
Qux function foo (string bar, bool baz) {
...
}---
I find the latter much more familiar than Typescript and less confusing. It's also slightly less verbose.
let user = new User();
let user: User = new User();The name is usually more important than the type so I like that typescript puts it first.
void function () { return 42; }(); // returns undefined
It's not something you would usually use in your code, but many Javascript minimizers make heavy use of it, and Typescript must know how to handle any valid Javascript without ambiguity.[0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
The current syntax seems better for type inference and gradual typing.
[0] https://learnxinyminutes.com/docs/ocaml/
[1] https://learnxinyminutes.com/docs/rust/
[2] https://learnxinyminutes.com/docs/kotlin/
[3] https://learnxinyminutes.com/docs/haxe/
[4] https://learnxinyminutes.com/docs/nim/
[5] https://learnxinyminutes.com/docs/swift/
[6] https://learnxinyminutes.com/docs/elm/
Typescript's type checking is slow and doesn't need to happen at runtime. Additionally, it moves failures to users rather than developers and makes it incredibly difficult to change type semantics later on.
https://devblogs.microsoft.com/typescript/a-proposal-for-typ...
Anyway, a simple version of JS or more like bytecode. Then developers can pick whichever language they want. Because these type annotations do not benefit execution, only development.
There is also a proposal for directly shipping ASTs instead of JavaScript source files for performance improvements [0].
Well this is why TypeScript was invented in the first place. Not to mention that "static-only" type annotations are being adopted in Python and Ruby as well. Clearly a lot of developers see a lot of value in them.
If you want a strongly-typed static language, compile to a wasm target with typescript, or another language... That's what it there for.
I'd rather have a proper type-less functional language and it's impossible to create that from JS with its legacy baggage.
You probably mean asm.js
As much as I love TS, integrating it into build or dev pipelines has repeatedly caused big headaches. Multi-stage source maps don't always get wired up correctly. Tools may understand TS or ESM, but not both.
I would very much like this proposal to get ratified, so that my pipelines can become simpler and more robust, and so I don't need TS flavors of normal JS tools.
> Having type "comments" seems like way less utility compared to what typescript offers
The proposal isn't taking away anything that TypeScript offers. It lets TypeScript layer its value (types enforcement) on top of plain .js files, without getting in between the source code and tools / runtimes.
More importantly, this doesn't add all of TS, so you'd still have to run those tools and nothing changes except that JS is now locked in to a syntax that may or may not be the best for an actual type system in the future.
Or you pass the code through a preprocessor to strip out the types and squash it before sending it to the client. At which point you have a pre-processor in your tool chain, and it might as well be a compiler from your favorite language (such as TypeScript).
I think this might be reinventing the wheel to insufficient benefit.
Right now when I'm authoring typescript in vscode, I get live error feedback from tsc and eslint in the editor, so in practice I only need to run tsc to "build" because I need to strip out all the typescript syntax. If that syntax became usable in a modern browser I could skip that build step during development and only run it for deploys to CI, staging and production.
curious to see, though, if popularity of other statically-typed compile-to-js languages will suffer if TypeScript syntax is adopted into the js spec (presumably causing TypeScript to gobble up more market-share).
[1] https://github.com/jashkenas/coffeescript/issues/5307 [2] https://github.com/jashkenas/coffeescript/issues/5394
> While these languages compile to JavaScript, and have static typing, they are not supersets of JavaScript, and thus are not relevant to this proposal.
https://github.com/giltayar/proposal-types-as-comments/#what...
https://peps.python.org/pep-0484/
It’s a fair compromise, though now there are two invariants: all untyped JS must be a subset of typed JS, which in turn must be a subset of Typescript. And if a JS builtin like Python’s “typing” module is added to make type definitions easier and standardized, there’s now two ways to define types in Typescript. Which is far from the end of the world… but still will be somewhat controversial.
(It was also used for optimization.)
Wouldn't comments be a better solution to this given the legacy?
Here's what I think the type system should allow at a minimum:
1. Scalar types (number, string)
2. Common union types (eg something that could be a number or a string)
3. This is a big one: nullability should be part of the type system;
4. Object typing that includes mandatory and optional keys and their legal types;
5. Array types (generics);
6. Dictionary types (generics); and
7. An unknown type (like "mixed" in Hack).
Part of this is you need the option of preserving types at runtime and doing runtime type enforcement. This should be optional to generate a "debug" build and can be stripped out. You should be able to assert types as well as turn on automatic type checking on entry and exit to function calls as a method of finding bugs.
These errors should also be available as a warning (ie print to console.log) or an error (fatal).
Lastly, you should be able to easily write a type error handler to capture such violations.
You could ... use a bundler, which would handle both js and ts files quite seamlessly.
Also the announcement: https://devblogs.microsoft.com/typescript/a-proposal-for-typ...
And HN discussion: https://news.ycombinator.com/item?id=30618681
.d.ts files contain a lot of things other than types for the emitted code. Interface types disappear completely when compiling TypeScript, but they are an important part of many .d.ts files, especially anything describing existing web APIs.
I read the FAQ in the proposal but don't understand the challenges in adding type introspection at runtime. It seems weird to add all this syntax and not have any way to leverage it during runtime. Although maybe it wouldn't be that useful? Still making up my mind about this.
Glad to see that these questions are at least being considered and explored as part of the proposal.
Great job from everyone involved, this proposal shows a lot of promise and it makes me excited for the future of JS.
The issue is, what should the browser do if it encounters a type error? Should it just refuse to interpret the entire script? That’s super heavy-handed when it’s possible that the error doesn’t even matter in practice.
Just because they're not leveraging them today, it doesn't mean that they won't do it tomorrow. If a proposal requires a big effort to implement it, it will probably never become adopted.
Why not just use typescript directly in the browser?
Yes, but if you compare Dart to ES6, ES6 is a much nicer language, so we got lucky that they failed.
What major features does JS/ES6 have that Dart lacks?
I want to write, run, and debug a js file in node without intermediate files. Repl speed would increase a lot.
Also, the parser performance will probably take a hit.
Is this "backporting" TS to JS or is there something else I'm missing?
[0] https://devblogs.microsoft.com/typescript/a-proposal-for-typ...
Originally Mypy was supposed to be a Python superset, like TypeScript, but instead its variable annotation syntax was adopted as Python syntax. It has been an interesting journey for Python, with a lot of ups and downs. Type hints, for all their productivity and bug-safety benefits in most cases, still feel like a bolt-on feature that requires developers to change how they write code, and in many cases favors less-performant idioms and/or extra boilerplate compared to un-hinted Python. Whereas TypeScript has a lot more freedom to mess with how things work, because it's a superset that compiles to JavaScript and not actual JavaScript.
So it's somewhat surprising to see this proposal for JavaScript, because the TypeScript model always seemed better in hindsight than the Python model! But maybe it's just a "grass is greener" situation.
Seems like a very reasonable proposal to me.
It is quite similar to Python's type hint system. Python's is kind of rubbish because there are multiple competing type checkers with different semantics and most people use the crap one (Mypy). I can't see that being a problem here - essentially everyone uses Typescript and it's very good.
idk, I wouldn't go this far. Mypy is slow, but it's probably the most correct, and it allows for configurations pyright refuses to. For instance, the maintainers won't add an option to allow variable redefinition/shadowing, seemingly because they don't understand the difference between a variable and a binding (https://github.com/microsoft/pyright/discussions/2441). As for Pyre, last I checked it had a lot of false positives that Mypy doesn't.
Besides all that, some people want to use a checker that isn't exclusively developed by a huge company (Microsoft, Google or Facebook).
In contrast Pyright seems to get pretty much everything right, even really subtle things, and if it is really a bug then the guy that maintains it is insanely good at fixing them. Seriously check out how many open/closed issues there are.
As for variable redefinition, Python stupidly doesn't prescribe semantics so it's perfectly valid for it to behave like that. Definitely arguable which way it should go and I think for clarity it's much better to use different names anyway. It's not because they don't understand anything.
Mypy has way crazier behaviours anyway, e.g. implicit making types optional. Different behaviour depending on the syntax used to add types, etc.
That's probably true of most code :P
>Definitely arguable which way it should go and I think for clarity it's much better to use different names anyway. It's not because they don't understand anything.
I agree it's debatable which behavior is better. The reason I claim a lack of understanding is because of a comment (albeit likely a flippant one) one of the maintainers made in the issue I linked:
>When a variable or parameter has a declared (annotated) type, it's the job of a type checker to validate that all values assigned to that variable are compatible with the declared type. This is how type checking works in all languages that I'm familiar with.
This just isn't true; many strongly-typed languages allow variable shadowing, especially within lexical scopes. Some, like Rust, even allow rebinding within the same scope.
"any" is the escape hatch and allows you to do anything with the variable. In essence it stops type checking entirely for that variable.
"unknown" takes the opposite approach and doesn't let you do anything with the variable value (other than pass it along to other "unknown" accepting variables/functions) until you have asserted its actual type with type guards.
False. I greatly enjoy writing minified code; not only is such golfing fun, you can regularly achieve drastically smaller results.
Automated JavaScript minifiers are a useful tool, but they all miss significant opportunities in even simple things like code reordering, because JavaScript’s semantics just don’t support that sort of thing.
It puzzles me, given how much effort has gone into making a slow language run faster than it has any right to, how little effort has gone into making any kind of optimising compiler, for both runtime performance and bundle size. GCC and LLVM put insane amounts of effort into optimising things, which work best when paired with something like Rust’s ownership model (… so long as rustc isn’t currently being conservative after having uncovered yet another bug in LLVM’s noalias!).
Meanwhile in JavaScript land, the main tool used is Terser, which is both simple and simplistic. It does very little in the way of optimisation, because it basically doesn’t seek to understand the code, and so can’t apply perform any operations that could change the semantics in such-and-such a situation that (if you tried harder) provably cannot occur. Long ago, Google made Closure Compiler, and it’s a good deal better, so long as you’re willing to humour the idiosyncrasies it requires in advanced optimisations mode, but it’s still far, far short of what GCC/LLVM can do. A few years ago, Facebook toyed with symbolic execution in Prepack, an approach with potential for building good tooling, but they gave up on it before it reached the point of being useful.
Then consider other popular tools in the ecosystem: Babel is stupid (by which I mean that it doesn’t attempt to understand the code) and generates significantly bloated code because it’s seeking to match semantics as perfectly as possible without questioning whether it needs to. Bublé demonstrated a different approach, where you say “eh, who cares about exact semantics, let’s just note down the caveats and generate simpler, smaller and faster code”. (For both of these tools, I’m talking about the old ES6+ → ES5 compilations, which are obsolete now; I’m actually not sure what people use Babel for now, and how much this judgement applies.) And for bundling, webpack, which… ugh, the code it generates is just wilfully inefficient. Rollup demonstrated a different approach, where you actually care about minimising code because it makes it smaller and faster.
So returning to the original point: I certainly write minified code sometimes. I have a few <script> blocks on my site (one on all pages, others on pages that use them), and those are hand-written, sometimes with an automated minifier’s help to rename variables for slightly better compression, but other than that, all manual. I’ve got a project I’ve been working on for doing DOM stuff off-thread with a tiny VM on the main thread to execute byte code, and in that I’m working the same way: I know I have to have a little main-thread JavaScript, but when automated minification can reduce my 5KB of nicely-factored code to 1934 bytes (~1185 gzipped), but manual minification can reduce it to 928 bytes (~417 gzipped) that will also run faster due to eliminating abstractions, well, I know which approach I’m going with. My way of working in these sorts of projects is that I maintain expanded and minified source codes simultaneously, and apply any changes to both.
You might say “why not work in semi-minified code, applying whatever minifying transformations you have except for variable naming and whitespace, then use an automated tool for that part?” and you would have a bit of a point, except that then I’d need to worry about naming things, which can be complicated by reusing variables. Eh. I enjoy it. It’s mostly fun.
A byte here, a byte there… ah, fond memories of my Casio CFX-9850GB Plus Color calculator too on which I spent hundreds of hours in my school days, often golfing my programs to save one or two bytes here or there, since I normally had at most a few kilobytes of storage space spare. I discovered at one point that they kind of had two instruction-ending characters, a line break, which was two bytes, and a 𝅍 sort of a character, which was one. Thereafter, all my source code was on one line. Those things were quite astonishing in their battery life, too; I would have racked up over 1,000 hours on it, but only went through four sets of four AA batteries. Meanwhile the newer model almost everyone else used, while about 4–10 times as fast depending on the operation, lacked colour and chewed through batteries around 40 times as fast. Then came CAS calculators, probably using 40 times as much power again…
I’m rambling, aren’t I?
Yet in my entire career I have found that I am the only dev that writes these comments. I use to think this was just JS devs but I have found C#, Java, and indeed Typescript projects that I work on to be sorely lacking in comments of any kind. So, how does this adding complexity to the language standard change this?
People won't use it in production because it is too big. In development, map files work fine and people will still use them because this isn't feature complete with TS.
At most, it locks JS into an unchangeable type syntax that may or may not work out.
Instead, we need a `use type` mode that fixes more of JS. I want type coercion gone and the super-dynamic parts of the language restricted (this both makes types more simple and makes the language more optimizable). I'd also like to see Option and Either types baked in and have `null` removed or severely restricted.