TypeScript team released an explorer for performance tuning(devblogs.microsoft.com)
devblogs.microsoft.com
TypeScript team released an explorer for performance tuning
https://devblogs.microsoft.com/typescript/introducing-deopt-explorer/
41 comments
This is... good news, but I still cannot fathom using the default Typescript compiler for regular development. Seriously, leave the type-checking to your IDE and CICD chain, and switch to using tsx (https://www.npmjs.com/package/tsx) or swc (https://swc.rs/) and you will _immediately_ notice the difference in speed and productivity.
Leaving type checking to the IDE can cause a lot of unforseen problems. IDE support is imperfect, especially if you have some legacy JS code you need to integrate with, and sometimes it's even unreliable.
The Typescript transpiler does definitely slow things down but I've tried the "only check types during build" approach and while it starts out very nice and quickly, you end up wasting all that time you would've waited on tsc by chasing down impossible to find typing bugs and doing the necessary code restructuring to fix the problems your IDE missed. Only finding out about these bugs when pushing code (or even worse, when opening a pull/merge request) can be a lot more annoying than giving tsc half a second to catch up.
I do wish that tsc was faster, but on the other hand I can't say it's been that much of a problem for me.
Perhaps this is because I'm almost exclusively on Linux. tsc operates on tons of tiny files and Windows is notoriously slow at dealing with that, even with AV exclusions.
The Typescript transpiler does definitely slow things down but I've tried the "only check types during build" approach and while it starts out very nice and quickly, you end up wasting all that time you would've waited on tsc by chasing down impossible to find typing bugs and doing the necessary code restructuring to fix the problems your IDE missed. Only finding out about these bugs when pushing code (or even worse, when opening a pull/merge request) can be a lot more annoying than giving tsc half a second to catch up.
I do wish that tsc was faster, but on the other hand I can't say it's been that much of a problem for me.
Perhaps this is because I'm almost exclusively on Linux. tsc operates on tons of tiny files and Windows is notoriously slow at dealing with that, even with AV exclusions.
I find the best middle ground is setting up the IDE to have TSC watch running while making changes, but using other tools for doing the actual compiling (vite for example). This allows me to refactor quickly - choosing when to ignore type errors - but also be notified of all the other call sites that I need to update, including in all of the files not currently open in the editor.
YMMV. I very rarely have the IDE and tsc disagree. Even though it happens occasionally, I'd much rather have instant type feedback as I work and have to fix some errant types with 10s+ feedback right before checking in than have 10s+ feedback all the time.
I just have such a hard time imagining how the other type checkers keep parity.
TypeScript doesn't evolve super fast, but there are a steady stream of great improvements. I'd be so afraid I have either less type checking, things that silently pass/aren't checked, or intelligence that TypeScript has that other checkers don't have.
Also, as others say, just using --watch largely eliminates the problems of using tsc. I haven't worked on any truly huge codebases but it's been quite snappy. It's a longshot, but I wish TypeScript would also be it's own LSP too.
I definitely did love love love how blazingly fast & super easy to work with, no setup, Deno was. Incredibly refreshing, no ceremony.
TypeScript doesn't evolve super fast, but there are a steady stream of great improvements. I'd be so afraid I have either less type checking, things that silently pass/aren't checked, or intelligence that TypeScript has that other checkers don't have.
Also, as others say, just using --watch largely eliminates the problems of using tsc. I haven't worked on any truly huge codebases but it's been quite snappy. It's a longshot, but I wish TypeScript would also be it's own LSP too.
I definitely did love love love how blazingly fast & super easy to work with, no setup, Deno was. Incredibly refreshing, no ceremony.
They don't keep parity. As far as I know, the official TypeScript implementation is the only major one that performs checking. There are tons of other options for stripping types that are much faster, but that's a much easier task
Deno uses tsc internally, and VSCode at least uses the official typescript language server, which I believe uses tsc internally
Deno uses tsc internally, and VSCode at least uses the official typescript language server, which I believe uses tsc internally
I wish there was also a much faster type checker!
I have absolutely 0 problems with the type checking that VSCode does. Always feel snappy. By comparison, command line performance is absolute crap though. The missing piece I suspect is a background daemon that auto-analyzes as you type like they do when you’re editing in VSCode to hide that latency. That’s a pretty standard technique to solve this problem (typically LSC although I don’t know how VSCode does TypeScript)
I was almost 100% certain that the typescript language support in VSCode was using the typescript language service library that's also used by tsc.
Sure but the command line version as best I can tell doesn’t bother keeping a long-lived tsc around. Sure, you can run it in watch mode but if you just run it it doesn’t bother doing that. For example, Facebook launches watchman to keep track of file modifications to files and keeps Buck’s dependency graph up to date so that Buck knows which targets are out of date instantly when you run the command. A more advanced version would know which targets you rebuild/run when you make a change like that and automatically refresh them. Same for running the tests.
I had a not so fast work laptop in my last work. Typescript compiler was very slow for relatively small project
Doesn’t the comment you just replied to link to one? (Tsx)
No. It’s based on esbuild which does not check types.
This is really impressive work, which can benefit other large JS tools.
I realise this is sort of a dead horse, but rewriting the Typescript checker in Rust would not be an impossible task for a team as well-resourced as Microsoft’s.
I know, because I rewrote a different 100KLOC typechecker myself in Rust (making a few small adjustments for a slightly different target language). It took me about a year.
It would speed up the TypeScript typechecker at least 3-5x, which would save a lot of programmer time (and also datacenter energy consumption).
There’s one obvious downside — it raises the bar for outside contributions — but given the expertise necessary to contribute usefully to a static analysis tool in the first place, and to contribute to TypeScript in particular, I’m not sure it’s a big additional impediment.
I realise this is sort of a dead horse, but rewriting the Typescript checker in Rust would not be an impossible task for a team as well-resourced as Microsoft’s.
I know, because I rewrote a different 100KLOC typechecker myself in Rust (making a few small adjustments for a slightly different target language). It took me about a year.
It would speed up the TypeScript typechecker at least 3-5x, which would save a lot of programmer time (and also datacenter energy consumption).
There’s one obvious downside — it raises the bar for outside contributions — but given the expertise necessary to contribute usefully to a static analysis tool in the first place, and to contribute to TypeScript in particular, I’m not sure it’s a big additional impediment.
A benefit of the typescript compiler being written in typescript is that the compiler-makers get to dogfood their own language.
Rewriting it in rust would remove that important aspect c
Rewriting it in rust would remove that important aspect c
Rust alone wouldn't help. TypeScript is very hard to compile and to understand because of its complexity. I think there is a need for a different architectural approach with huge parallelization. Some (CI) servers have plenty of cores. Heck, my laptop has 20 threads.
The approach is simple (I've implemented it, and so have many others):
It takes three steps. Steps 1 and 3 are parellisable, and 2 should be very quick:
1. Convert every file in the repository to an AST, and perform static reflection on that AST.
2. Calcuate the inheritance graph for all the functions, classes etc. you've collected
3. Analyse every file, using the pre-calculated list of functions and classes available in each case.
It takes three steps. Steps 1 and 3 are parellisable, and 2 should be very quick:
1. Convert every file in the repository to an AST, and perform static reflection on that AST.
2. Calcuate the inheritance graph for all the functions, classes etc. you've collected
3. Analyse every file, using the pre-calculated list of functions and classes available in each case.
swc and tsx are already significantly faster than tsc, partly due to being written in faster languages, or languages that make it easier to write fast code with minimal runtimes.
Neither of those check types. It’s easy to be fast when all you’re doing is filtering out type-bytes (and perhaps some transpiling). That’s nothing compared to actually type checking, which requires solving complex satisfiability problems across the entire codebase.
My understanding was that TypeScript would be more parellisable than Flow, which itself is plenty parallelisable: https://arxiv.org/pdf/1708.08021.pdf
Call me crazy, but I prefer single threaded. It limits the potential impact on the rest of the system, and all cloud payment is by the core•hour anyways.
Do they check types?
Sorry, my previous comment wasn't very clear. Of course, faster languages produce faster results. But the language alone isn't enough in this case.
Sorry, my previous comment wasn't very clear. Of course, faster languages produce faster results. But the language alone isn't enough in this case.
Yeah, that helps them stay close to the community and prevents any air of superiority that can come from writing Rust.
But, while I’m sure it was really important initially, there are now very many test cases and early-adopters to help prevent regressions.
And they still have that large TypeScript codebase to test their new tool on — it wouldn’t vanish.
But, while I’m sure it was really important initially, there are now very many test cases and early-adopters to help prevent regressions.
And they still have that large TypeScript codebase to test their new tool on — it wouldn’t vanish.
Note that there’s at least one TypeScript type checker being developed in Rust by a third party:
https://github.com/dudykr/stc
https://github.com/dudykr/stc
> I know, because I rewrote a different 100KLOC typechecker myself in Rust (making a few small adjustments for a slightly different target language). It took me about a year.
It sounds like you could easily have a nice consulting gig for Microsoft.
It sounds like you could easily have a nice consulting gig for Microsoft.
Extremely cool. It's crazy to think that the team built such an advanced tool for themselves, which very few other JS codebases can even benefit from. But the results speak for themselves, it was clearly worthwhile
Is there any effort to get browsers to support typescript? Transpiling is great, but all the tooling required by a typescript project, from transpiling to barreling, is becoming daunting.
You're mixing a couple of ideas. There is a proposal[1] to allow for type annotations in the browser but it's only a subset of what's possible in TS. As for barreling/bundling, that's never been a goal for TypeScript. That's handled by tools like Webpack and ESBuild. In fact, there's an effort going the opposite direction. As browsers support ES style modules, we don't need to bundle anymore as the browser will load the relevant files as needed
[1] https://github.com/tc39/proposal-type-annotations
[2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...
[1] https://github.com/tc39/proposal-type-annotations
[2] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...
I like the idea of JS modules but they don't entirely negate the need for bundling. Sending a single compressed, tree shaken, minified JS file down the pipe can be a lot more efficient than waiting for the browser to load all those files.
Theoretically HTTP/2 push could've helped here, forcing the necessary files into the browser cache, but that's been removed from browsers.
Theoretically HTTP/2 push could've helped here, forcing the necessary files into the browser cache, but that's been removed from browsers.
Agreed. To me, browser support for modules is great for debugging but is not a suitable replacement for producing an optimized set of bundles
No, but the TypeScript compiler will also check types specified in JSDoc: https://devclass.com/2023/05/11/typescript-is-not-worth-it-f...
https://www.typescriptlang.org/docs/handbook/jsdoc-supported...
https://www.typescriptlang.org/docs/handbook/jsdoc-supported...
> Is there any effort to get browsers to support typescript
You may want to read
https://news.ycombinator.com/item?id=35187377
https://news.ycombinator.com/item?id=35653653
Transpiling is entirely optional. Choose "esnext" as target and don't use the old and no longer needed "namespace" (now: just use modules) and "enum" (now: just use an object literal annotated with "as const") - and all that is done is removal of the type annotations.
If you write Typescript you already write pure Javascript, you just add type annotations, which are not part of the code and don't make it into the code.
Typescript mixes type checking and transpiler (Babel) and a few other thing in one big "blob" of a tool - unfortunately, the Unix way would have been to have separate tools. Which you can do and many do: Don't use "tsc" to create your .js code, only use it (through the IDE or standalone) to check types, and let Babel do any transpilations. It's much more flexible than "tsc" too.
What you are really asking is "Is there an effort to add types to ECMAscript" - and that does not look likely, because a) the existing solution already works well enough, and b) if you look at all the troubles and limitations you get when you use types you realize adding types is nearly impossible if you want to remain backwards compatible. If you use typed code, e.g. by using Typescript or Flow, you either end up with a lot of "any" types, or you have to code for the type checker. You cannot add reliable types to any previously pure Javascript code base. The code itself would have to change. Also, enough people don't want any types with their JS.
You may want to read
https://news.ycombinator.com/item?id=35187377
https://news.ycombinator.com/item?id=35653653
Transpiling is entirely optional. Choose "esnext" as target and don't use the old and no longer needed "namespace" (now: just use modules) and "enum" (now: just use an object literal annotated with "as const") - and all that is done is removal of the type annotations.
If you write Typescript you already write pure Javascript, you just add type annotations, which are not part of the code and don't make it into the code.
Typescript mixes type checking and transpiler (Babel) and a few other thing in one big "blob" of a tool - unfortunately, the Unix way would have been to have separate tools. Which you can do and many do: Don't use "tsc" to create your .js code, only use it (through the IDE or standalone) to check types, and let Babel do any transpilations. It's much more flexible than "tsc" too.
What you are really asking is "Is there an effort to add types to ECMAscript" - and that does not look likely, because a) the existing solution already works well enough, and b) if you look at all the troubles and limitations you get when you use types you realize adding types is nearly impossible if you want to remain backwards compatible. If you use typed code, e.g. by using Typescript or Flow, you either end up with a lot of "any" types, or you have to code for the type checker. You cannot add reliable types to any previously pure Javascript code base. The code itself would have to change. Also, enough people don't want any types with their JS.
> no longer needed "namespace" (now: just use modules) and "enum" (now: just use an object literal annotated with "as const") - and all that is done is removal of the type annotations.
Both these things are needed. The workarounds you listed are not equivalent and not drop in replacements.
Both these things are needed. The workarounds you listed are not equivalent and not drop in replacements.
No they are not needed.
See these and many similar statements/posts.
https://michelenasti.com/2019/01/23/is-typescript-namespace-...
https://stackoverflow.com/questions/64495793/typescript-name...
https://github.com/microsoft/TypeScript/issues/30994#issueco... (link to a specific comment)
> Namespaces are probably never going away and, simultaneously, you probably shouldn't use them, since better, more standard and modern patterns exist through the use of modules. If you have code that you feel needs to use a namespace, more power to you and go for it, but most of the time you don't need one, as we now have a different conceptual organizational model recommended for large-scale JS (modules). That's why @DanielRosenwasser (Program Manager of TypeScript) said namespaces are not a huge loss - most new TS code should probably never need to use them, and should think hard about if they really need to.
Sure, you can use them, enums as well still provide a few more options than object literals, and since those features are in TS anyway and will remain like everything in JS always remains for backwards compatibility... - but they are not needed.
There even is a sentence in the TS documentation (under Namespaces and Modules) that starts with "If you’re converting a program from namespaces to modules,..." (see https://www.typescriptlang.org/docs/handbook/namespaces-and-...)
This is distorting my post's point, which was Typescript is ECMAscript, and I did mention the two big exceptions, and I said they are not needed - which is just truth. They were necessary before ES 2015, which is the reason they exist to begin with. Other than that, Microsoft's explicitly stated goal is to keep Typescript perfectly aligned with ECMAScript, and to only add types.
Now that the language has all the minimum features they don't make any more changes that require actual transpiling because the code itself - not the types - is "Typescript only" and not part of ECMAScript. They will, however, leave in anything that is already there, just like ECMAScript does, because backwards compatibility trumps all.
Also note that you can have types-only namespaces that only contain type definitions, which are entirely different: They fall exactly under what I said, types are just removed in the .js file generation step. Those kinds of "namespaces" don't lead to any executable code.
Not to mention that you could easily just write the tiny bit of JS yourself instead of using the namespace keyword, because namespaces are simply named JavaScript objects in the global namespace. -- This is all it does: https://www.typescriptlang.org/play?noUnusedLocals=true&noUn...
So if you want the same thing as TS namespaces with just JS code, all you need is a global object and then assign stuff to it, from one or from several modules.
See these and many similar statements/posts.
https://michelenasti.com/2019/01/23/is-typescript-namespace-...
https://stackoverflow.com/questions/64495793/typescript-name...
https://github.com/microsoft/TypeScript/issues/30994#issueco... (link to a specific comment)
> Namespaces are probably never going away and, simultaneously, you probably shouldn't use them, since better, more standard and modern patterns exist through the use of modules. If you have code that you feel needs to use a namespace, more power to you and go for it, but most of the time you don't need one, as we now have a different conceptual organizational model recommended for large-scale JS (modules). That's why @DanielRosenwasser (Program Manager of TypeScript) said namespaces are not a huge loss - most new TS code should probably never need to use them, and should think hard about if they really need to.
Sure, you can use them, enums as well still provide a few more options than object literals, and since those features are in TS anyway and will remain like everything in JS always remains for backwards compatibility... - but they are not needed.
There even is a sentence in the TS documentation (under Namespaces and Modules) that starts with "If you’re converting a program from namespaces to modules,..." (see https://www.typescriptlang.org/docs/handbook/namespaces-and-...)
This is distorting my post's point, which was Typescript is ECMAscript, and I did mention the two big exceptions, and I said they are not needed - which is just truth. They were necessary before ES 2015, which is the reason they exist to begin with. Other than that, Microsoft's explicitly stated goal is to keep Typescript perfectly aligned with ECMAScript, and to only add types.
Now that the language has all the minimum features they don't make any more changes that require actual transpiling because the code itself - not the types - is "Typescript only" and not part of ECMAScript. They will, however, leave in anything that is already there, just like ECMAScript does, because backwards compatibility trumps all.
Also note that you can have types-only namespaces that only contain type definitions, which are entirely different: They fall exactly under what I said, types are just removed in the .js file generation step. Those kinds of "namespaces" don't lead to any executable code.
Not to mention that you could easily just write the tiny bit of JS yourself instead of using the namespace keyword, because namespaces are simply named JavaScript objects in the global namespace. -- This is all it does: https://www.typescriptlang.org/play?noUnusedLocals=true&noUn...
So if you want the same thing as TS namespaces with just JS code, all you need is a global object and then assign stuff to it, from one or from several modules.
The comment below the one you linked is why namespaces remain useful:
https://www.typescriptlang.org/docs/handbook/declaration-mer...
It's a stretch to say "they're not needed." Like the comments in the threads you linked, they are usually not necessary for code written with esm modules in mind. However, modules cannot express the same semantics that namespaces can, and if you need those semantics for your program, you need namespaces.
Similarly, enums are not semantically equivalent to object literals with const fields, and I think it's kind of absurd to say that one of the most useful things in the TS type system is "not needed.
https://www.typescriptlang.org/docs/handbook/declaration-mer...
It's a stretch to say "they're not needed." Like the comments in the threads you linked, they are usually not necessary for code written with esm modules in mind. However, modules cannot express the same semantics that namespaces can, and if you need those semantics for your program, you need namespaces.
Similarly, enums are not semantically equivalent to object literals with const fields, and I think it's kind of absurd to say that one of the most useful things in the TS type system is "not needed.
YES! I use that myself! It's the only way to extend an existing type from different modules. Use an interface and make use of the automatic declaration merging, and for that to be triggered it needs to be in the same namespace. Which since modules are each their own namespace needs the "namespace" declaration.
But that is for TYPES and does not produce any JS code!
> Similarly, enums are not semantically equivalent to object literals with const fields
I know and I mentioned it! That still does not make them needed! You can use them if you want. As I mentioned.
> I think it's kind of absurd to say that one of the most useful things in the TS type system is "not needed.
I on the other hand think it's absurd to pretend to have a serious discussion when you claim that enums are "one of the most useful things" in TS. Some very minor syntactic sugar add-on as one of the main points of type checks???
But that is for TYPES and does not produce any JS code!
> Similarly, enums are not semantically equivalent to object literals with const fields
I know and I mentioned it! That still does not make them needed! You can use them if you want. As I mentioned.
> I think it's kind of absurd to say that one of the most useful things in the TS type system is "not needed.
I on the other hand think it's absurd to pretend to have a serious discussion when you claim that enums are "one of the most useful things" in TS. Some very minor syntactic sugar add-on as one of the main points of type checks???
Deno is a nice project for running TS without a separate transpile process, but that's server-side only.
Browser-side, they tried to add support for a second language via Dart, but that didn't work out.
Browser-side, they tried to add support for a second language via Dart, but that didn't work out.
On the server side, you can use bun instead of node.