5 ms·
Running the typechecker independently of the bundler is really common in TypeScript. Typechecking takes time, and blocking on it to transpile and bundle your JS
by bichiliad 4y ago
Running the typechecker independently of the bundler is really common in TypeScript. Typechecking takes time, and blocking on it to transpile and bundle your JS doesn't really add any benefit. Most build systems run the checker in parallel because it cuts down on build time. Plus, Webpack doesn't really do transpiling or typechecking for you — your loaders do. Webpack's loaders can't really check your types because, without doing a lot of extra magic, they operate on one file at a time. If you use Babel with Webpack, for example, Babel just strips out your TypeScript annotations and calls it a day.
All that aside, it seems like Turbopack was literally developed with Webpack's maintainer, who claims it to be a "rust-powered successor to webpack" (his signature is quite literally on the homepage[0]).
[0]:https://turbo.build/pack https://turbo.build/pack
- Nathanba 4y ago>Running the typechecker independently of the bundler is really common in TypeScript maybe it is common, I can't speak to that but in my opinion a large part of the success of webpack was probably because they bundled the typechecking. Because that's the only workflow that makes sense, imagine a c# compiler that quickly outputs executable IL code but half the time it's broken because it didn't do any type checking and you have to wait for the IDE based type checker anyway. On every build. It just doesn't make sense to work this way, you never want a fast, silently broken build which is what you get with non-typechecked fast builds.
- peterhunt 4y agoNo, webpack became popular because it was the only bundler that supported commonjs and handled code splitting reasonably well, so we picked it for React. It's critical to run type checking outside of webpack. You should be able to execute code that does not type check correctly. It maximizes iteration speed and is one of TypeScript's key superpowers.
- bmy78 4y agoJavaScript is a dynamically-typed language. Parallelizing the type checking with bundling gives you the best of both worlds: the speed when writing in a dynamic language and the type safety that comes with a static-typed language. For me, I like to write my code and not too concern myself with types until I’m close to committing; that’s when I fix type errors.
- friendzis 4y ago> I like to write my code and not too concern myself with types until I’m close to committing I'm genuinely curious here. How do you ensure contract correctness? The whole point of static typing (or rather explicit typing) is to declare and enforce certain contract constraints prior to writing [client] code, which prevents certain bugs. What's the point of using type-safe language if you deliberately circumvent type safety? If you "fix type errors" by declaring things to be strings you do not get much more type safety from TS than plain JS. Or am I hugely missing something here?
- Vinnl 4y agoYou ensure contract correctness by encoding it in the types. However, while developing, you might still be figuring out the contract.
- bichiliad 4y agoThis is a good question. I had a hard time drawing a line between perfect type contracts and dealing with JavaScript's idiosyncrasies. There is a lot of behavior in JS that is very hard to produce strong, reliable types for. If someone overwrites a prototype somewhere, your types are probably incorrect no matter what you do. Add in the fact that TS types can't really be accessed at runtime (mostly) and it makes type guarantees even harder to enforce with 100% accuracy. It helps to think of TS types as a guarantee of behavior and an encoding of intention, and of TS itself as a really smart linter. As long as you use my function according to these types, it'll behave as expected. If it doesn't, that's my problem and I'll fix it. If I say my function returns a string, you can use my function's return types as a string with the confidence that that's how I expected it to be used. TS will make sure that everything agrees with my type assertion, which removes the need for checking the types of parameters in tests, for example.
- MrJohz 4y agoWebpack does not bundle the type checking by default - iirc it cannot handle typescript at all by default, it needs to be configured. The typescript plugin that you used may have included type checking, but it very much depends on how you set it up. Many common setups use Babel to compile typescript code, which doesn't do any type checking at all, just mechanically strips away the type signatures. I would be very surprised if much of webpack's success has come from the type checking functionality you describe. As for whether it's "the only workflow that makes sense", I find the most comfortable flow for me is using the compiler as a linter rather than a "true" compiler. It runs in my IDE, potentially as a pre-commit script, and in CI (which means checked in code cannot fail to type check), but I can still build failing code. This would be, as you say strange if I were using C#, but syntactically valid typescript can always be covered to syntactically valid javascript, so the output won't be "broken" in the same way that a C# program with invalid types would be. Most of the time, a program that isn't accepted by TSC is still a valid javascript program, just with poorly specified input and output types. That said, while it can be useful occasionally if I'm still trying to figure out the types, the advantage here is less that I can now compile invalid code, and more that my bundler doesn't need to do unnecessary type checking. Any errors I can catch myself based on the red squiggles in my editor, so I know not to look at the browser until I've fixed all the issues, and at that point I don't need my bundler to also confirm that the types are accurate. Each tool does one task well. (Similarly, I don't want my bundler to also run all the unit tests before it compiles, even though I would normally expect the tests to be passing before I check the output of my code. 90% of the time, if I run the bundler, my tests are passing, and in the last 10%, I probably want to quickly try something out without changing the tests. The same logic usually applies to my types.) As a result, I strongly disagree with the claim that your process is the only one that makes sense. It may be the most logical for you and your team, but I tend to find that it makes sense to approach typescript from a different angle to most typical compiled languages, and I've found a lot of success in my process.
- Nathanba 4y agoI think maybe the underlying problem here is that some people somehow manage to write javascript inside .ts files and I haven't figured out how they do that. I doubt it though, I think there is no way. It always complains about lack of types, it wants me to add annotations. The promise of mixing js and ts is not real for me. It just defies belief for me that people actually want to write squiggly line, broken autocomplete type of code and have it compile a tiny bit faster compared to just having a single unified workflow where typing, build output and build information always matches and you don't have to guess and look up whether the build is already done, or maybe there was a build error or maybe this time one of the type checks that I ignored actually mattered for js also, not just for ts or maybe the error was actually not just a typecheck error but also a DOM api error and on and on it goes. To actually want to live in this world of uncertain, mismatched information and expect to be faster iteratively is not believable. How is it not a problem for you that you make a change in a .ts file and then you are immediately in a world of uncertainty: Is the typecheck already complete? No clear progress on this. The js output is probably already here, but not sure unless you constantly want to check yet another terminal window. So can I reload the page yet? Oh no wait, a few more type errors popped up after all, so I can't yet. This all happens in under 2 seconds but those 2 seconds are uncertainty and slow you down far more than any wait for a normal sized typescript project where typechecking is done integrated with the build.
- jatins 4y agoTypescript is different from C# in that it is a superset of Javascript. That is even a wrongly typed typescript is valid JS code. IMO it makes sense to allow bundling if that enabled you to get things like fast refresh. Sometimes you just want to make a change and see the result on browser without worrying about types.
- johnny_reilly 4y agots-loader maintainer here. webpack never did typechecking. It's possible to run ts-loader in two modes; with type checking active and with it disabled. For years I've been advising running type checking as a separate process to improve the development workflow: https://blog.johnnyreilly.com/2017/09/07/typescript-webpack-super-pursuit-mode/ https://blog.johnnyreilly.com/2017/09/07/typescript-webpack-... Exciting news about turbopack - the world is about to get much faster!
- bichiliad 4y agoThank you for ts-loader!
- Vinnl 4y agoOne thing I haven't seen mentioned yet in the replies is that often, people will already have type checking in their editor, with inline feedback. The iteration speed when it comes to fixing type errors is much faster that way, and then running type checking again to serve it up in the browser is unnecessarily slowing you down (and the type checker isn't really fast).
- bichiliad 4y agoAnother thing worth pointing out is that pretty much every editor that ha a TypeScript plugin uses TypeScript's language server to power it. The language server and the compiler are contained within the same binary (or at least they were) and use the same typechecking logic. So if you see an error in your IDE, you can be pretty confident that it'll be there when you build your code, and vice versa.
- solarkraft 4y ago> imagine a c# compiler that quickly outputs executable IL code Awesome! > but half the time it's broken because it didn't do any type checking and you have to wait for the IDE based type checker anyway. On every build. Huh? The IDE checks your types as you type. Not on every build. This works great and de-duplicates effort. I have an extra "check" script that runs all the linters including the Typescript checker that you can run before making a PR or production build (tells you the same thing as the IDE). I'm glad it doesn't block my development build because it takes many seconds (10-20) while without it you can get updates in far below one. That's a night and day difference. > you never want a fast, silently broken build which is what you get with non-typechecked fast builds. You're misinformed about what I want. I want fast builds. Decoupling linting from building is a great way to achieve that. I am yet to experience any problems with it. If you want to type check on every build you can put that into your pipeline, but it will unnecessarily slow things down. I for one am very happy with fast builds with no downside.
- i_like_robots 4y ago> Webpack's loaders can't really check your types because, without doing a lot of extra magic, they operate on one file at a time. This is the point folks really must understand when setting up a new tooling pipeline to deal with TypeScript. Certainly all of the module bundlers I'm aware of operate in this way. To explain further for anyone curious; for TSC to work effectively it must construct and understand the entire "compilation". To do this it starts by performing a glob match (according to your include/exlude rules) to find every TypeScript file within the project. Resolving and type checking the entire compilation every time the bundler calls for a transform on a file is very slow due to lots of repeated and unnecesssary work so most TS bundler plugins have to work around this. Unfortunately, they're still relatively slow so type checking and bundling code separately is often the best way to go.
- Nathanba 4y agoBut in theory type checks could be cached too. Why this isn't currently done is because it's probably more work and requires very deep knowledge of the typescript language and parsing. Meanwhile the bundling itself is a simple affair of combining text files together. So these tools instead just fork the typechecker for some minor gain but in practice you could absolutely cache type information. That's what every IDE does with their intellisense database. I think in this thread we are essentially talking back and forth over the current state of bundlers and most here rationalize why it's okay (if not better!) for type checking to be separated from the compilation but the reality is that it's a fairly arbitrary state of affairs. It could easily all be efficient so that type checking is just as parallelized and incremental as bundling and therefore requires no separation into a different process. As we know, after all a binary produced by c++, rust or c# is also a "bundle". Actually this painfully reminds me why I found it so weird that tsc doesn't simply offer bundling itself. Why wouldn't it? It should be very easy for the compiler to do this as it has all the information and on top of that, tsc also has an incremental mode already. That definitely means 'incremental' for type information.
- pas 4y agotsc already has incremental mode, also there's the LSP, the bundler in watch mode could keep a persistent TS language server running. if the typecheck succeeds the bundler emits the new bundle, easy peasy. If I remember correctly gulp(js) was perfectly able to do this.