Most of the popular large JS projects have switched (or are switching) to TypeScript (or Flow for React, though they'd have used TypeScript today). So that supports the argument in favor of TypeScript.
Static types massively make it easier to understand new code. I can actually see the structure of the data that's getting passed around, with types.
Heck just getting auto-complete on an object's members.
A few layers of higher order functions / combinators and I don't remember if I have `value` or a `{ value: value }` container (like map vs flatMap). Or which stage of the curry I'm at. Oh right, I'm at foo(a, _, c) but thought I was at foo(a, b, _).
If you can't even remember the last time you've encountered a runtime error, you are by my definition writing trivial code or not writing much code at all.
I'm starting to feel behind the curve and I want to learn new stacks like Next.js, Typescript and GraphQL. Anyone else feeling this way or have already gone through that learning curve?
Next.js and GraphQL are interesting technologies, but I would say they will eventually fade. They do solve some problems, but they introduce new (hard to fix) ones.
Typescript is here to stay. The improvement it brings to the development experience cannot be understated.
It helps the inexperienced to avoid lots of (minor) bugs and providing much more useful autocompletion/inline docs than any javascript analyzer can.
For the experienced people, it is an invaluable tool when the time for largeish refactorings comes. For the first time you can "follow-the-trail-of-errors refactor" in frontend-land.
I am guessing that Next.js and GraphQL will be long-dead and obsolete "soon" (in the same way that e.g. jQuery & AngularJS were once also red-hot technologies but are now out of favor), but TypeScript really feels like it is here to stay with significant benefits. I guess this is a "learn technologies, not libraries" type thing?
I was "forced" to learn TypeScript for Angular 2 (that was the library of choice at where I worked at the time) but now also use it for my personal stuff out of choice.
Compared to pure JS it is a bit of a pain to get basic development up and running (since you need a TS -> JS compile step before you load it in the browser, unlike raw JS that you can just code and reload). For that I have created myself simple boiler-plate templates (1) that I use to bootstrap a new project so I can be up and running in a browser in 60 seconds etc (the template will do all the compilation and bundling for you using webpack)
Not as safe of course, but you get 90% of the benefits.
Yes, sometimes you'll run into weird cases where you have to wrestle the type system, but honestly, in the worst-case you can just ts-ignore those (though you probably want to minimize that).
If you haven't worked with a statically typed, compile-time type-checked language before, I think you owe it to yourself to learn one, whether or not TypeScript is the one you learn.
Whether porting existing projects to TypeScript is worth it is of course a question that cannot be answered universally. Depending on how… creative developers were when creating it, it can be incredibly mind-bending.
Typescript is really just a tool for people who want autocomplete in VSCode for their javascript, or who really still want to be coding in C# and unless you're just dying without those things it's a lot of overhead for not much benefit.
E.g. if I need to add a Bar property to a Foo object, in plain JS you just do it as and when you need to without any extra hassle. This makes hacking something together really fast and low-friction which is nice.
Typescript wont let you do that though - you need to go off and define the Bar property on Foo which you might argue slows you down, or seems inappropriate if you only need Bar in certain circumstances and not every time or whatever.
Personally I find that the extra rigor that Typescript forces is way worth the extra hassle - it prevents so many subtle bugs, makes refactoring a lot easier, helps multiple people work together on the same code in a sensible way, and IDEs work so much better (in my experience at least).
Most popular libraries by the way all have the types defined already - check out https://definitelytyped.org/
So in development, I am hack together things and though the type checker complains and my IDE shows plenty of red marks, it will still compile.
Once I’m don’t experimenting, I fix the type errors, and refactor.
I just want to add a property to an object. All I have to do is add it to the definition, and TS will show me every location I have forgotten to set the Bar property, which means I can be confident it is set, so I do not need to write extra code that tests whether Bar is set.
People don't use static typing for writing code faster, they use it for code that can be READ (and understood) much faster, especially by somebody who doesn't work with that specific piece of code every day.
I think it's generally agreed that in most situations, reading code is much more common than writing code, so static typing really make sense.
Only in the beginning / short-term when the project is new, small, and fits in your head.
IMO doesn't take much more code and complexity for it to switch over to statically-typed code being faster to write.
As an extreme example, I run an online strategy game implemented in Elm. The game only supported three melee classes but the community made really good points about how ranged classes should work.
I came back to a codebase I hadn't touched in over a year, picked a spot in the code where I knew my physics would have to be updated to handle projectiles, started implementing it, and I basically followed the compile errors until my physics system supported projectiles.
Had it been dynamically-typed, this kind of refactor/overhaul would have required me to recredentialize in much more code and either rewrite tests and/or manually test my code branches at runtime to track down errors. It would have taken much much longer.
You nailed it.
I agree, this is the biggest benefit of static types.
I worked at on a several hundred thousand line JS code base at a company, and people were passing objects around, and it was extremely painful to trace code and figure what the structure of the object was. I had to set a breakpoint in the browser, and inspect the object during runtime. Moreover, some fields would randomly be missing, because the field wasn't necessary for that instance of the object. It was infuriatingly maddening.
I ended up spending a lot of time adding Flow types to it, of the form:
type Foobar = {
someField1: string,
someField2: number,
someField3: Baz,
fieldThatIsNotAlwaysThere: ?Qux
...
}
The untyped state of the code base gave me an extremely hard to resist to add Flow static types wherever I could. I also added a step to the pipeline (with my manager's support) that would break the pipeline and make it impossible to merge new code, if it didn't have Flow static types (and I used flow-coverage to make sure the "any" keyword wasn't being used excessively to side step Flow type checking). I was told by some of my teammates to stop forcing types down their throat. I eventually spent so much reworking large parts of the code base, and adding static types to it that my other work suffered (and I wasn't putting as much time as I should have into it), that I was told to stop spending so much time on adding Flow static types. But it was hard to resist the temptation. When I had to implement a new feature / change a file, I would add Flow types to it, and then be drawn to adding types to the various other files that it connects to (imports from, passes data to, etc). They fired me in the end, for that (not prioritizing the things I was supposed to do well enough) and other reasons (was going through relationship issues and eventually a bad breakup, which caused associated psychological/personal/self-care issues).I've learned my lesson. Dynamic types aren't my cup of tea, and I find dynamically typed code to be repulsive and quite nauseating.
I would love to have static types in JS, but not at the expense of node.. and not just so people who are in different situations than mine are happy, because I act as if I was in their situation.
I personally love TypeScript, but I do have one big hang up. Janky builds in testing. Can't explain it, but sometimes the guarantees TS is supposed to provide don't compile over. Mainly while using nodemon or another auto compile. Have only ran into it a couple times, but it mainly crops up during module linking.
Also keep in mind you can use as modules via require('') and skip adding types to a js lib. Be sure to add --module commonjs or the equivalent in config.
Why I like TypeScript for myself is writing modules and api's. Mainly: inline documentation. And the pursuit of more of a deterministic outcome in your programs. Still the linking issue bothers me.
If it seems more hassle then it's worth for what you're working on, the rest of your team isn't bothered, and your clients are happy you don't have to worry too much. I still throw in vanilla JS on other smaller projects every once in a while for those reasons.
[1 EDIT] at most? hahaha.
Besides that, I've never been a Microsoft fanboy(to say the least) and it's worrying me that almost the entire JS eco system falls in the hands of that company; Github, VSCode, Typescript, NPM, etc.. Am I alone in this?
There is so much good stuff in the JS world, but we seem to adhere to a few companies and a few systems more and more. Being a 'Javascript' developer today only has very little to do with Javascript. It's about React, Redux, Hooks, ESLint, Prettier, Typescript, etc.. Oh, and don't forget to do it Agile, another joy and productivity killer. And when you don't agree with this stack you're either not so smart or still need to learn to 'understand' it.
Typescript in my experience has felt like a collection of hacks more than a well thought out expansion of Javascript. Additionally, it concerns me that official solutions to some problems (e.g. iterating on an enum) require you to write around the code that the compiler will generate. That does not fill me with confidence at all.
As a personal point of contention, I really dislike that the types are useless beyond design-time. But since they don't want to go outside the EMCA spec, we'll likely not see anything like pattern matching on type or type-level destructuring anytime soon.
As it stands, some trivial things can become a nightmare very quickly. Maybe I'm just used to the ease at which ML-family languages can express some concepts.
I can only surmise that things are moving in this direction to lower the barrier to entry. As more developers are working with JavaScript it's easier to subscribe to tools to manage consistency than it is to educate and rely on developers' standards to create working efficient code.
Thinking back I've worked on some massive 'Web app' projects over the last 20 years, and the biggest I worked on didn't use much in the way of frameworks or libraries, and standards were maintained by peer review and documentation.
Typescript I suppose automates a lot of this, but I don't think that makes it better.
Lately I have started using FastAPI in Python, which uses Pydantic to enforce type hints at runtime. This saves a lot of manual checking code (e.g. "if input_data["mykey"] == "unhappy path": raise ValidationError").
This was the same annoyance in Node.js because the types are so flimsy and manually checking is really boring. Tests are great but if you can have correctness while rapidly prototyping that would seem to be a win.
Is there a great TS lib to do runtime type reflection like Pydantic?
At the end of the day, they are just tools and how we use them is what really matters.
Typescript will pick up the JSDoc type annotations and use them to type the code. This can be a great option when typing an existing project.
Docs: https://www.typescriptlang.org/docs/handbook/type-checking-j...
Recently, Typescript was complaining about an implicit `any` even though the VSCode tooltip clearly could infer the actual type (it confusingly was showing both cases in the tooltip). I finally realized that VSCode's built-in inference worked here but Typescript didn't work at all because I forgot I was importing a .js file rather than a .ts file.
VSCode for course also downloads @types/* files in the background even in vanilla JS projects which is super helpful because you get effortless intellisense. That it does this kind of stuff out of the box is the sort of reason why I've lost my Vim/Emacs fanaticism over the years.
It doesn't auto-download @types, but it does suggest them to you. It can also auto-import, rename across files, etc.
Re-using types (structs or union types) is also a huge pain.
For example, does the code get compiled using a bundler like webpack? if yes how do you solve the import '../../../../../shared.ts' problem? Or do you use node modules in a monorepo? Compared to other languages I found these questions surprisingly difficult to answer and solutions often quite cumbersome, e.g. if I want to share one small file in my project I don't want to maintain a public npm module for it...
We use a single git repo with no npm packages defined, other than the package.json in the root because we have to put dependencies etc. in there. The directory structure for our source code is dead simple:
src/server
src/client
src/common
For example, the API endpoint definitions are common code, so you'll see stuff like this in client code that uses the API: import * as quizApi from "../../common/api/pages/quiz"
The ".."s are annoying, but working around them isn't worth the effort. Even when we heavily reorganize the file organization, it only ends up taking a few minutes to mechanically update these imports with a vim macro, or even with sed if it's a perfectly mechanical change.We run two copies of tsc: one for the client and one for the server, building to build/server and build/client. That results in a weird build directory structure:
src/server/db.js
src/client/app.tsx
src/common/endpoints.ts
build/server/server/db.js
build/server/common/endpoints.ts
build/client/client/app.tsx
build/client/common/endpoints.ts
If you need separate build settings for client and server, this weirdness is going to show up one way or another. However, we only introduced this build separation in the last month or so. For the first 1.5 years of the project, we got away with a single tsc process and tsconfig.json, with no build separation at all between client and server. If anyone who's newer to TS reads this, I'd encourage looking for simple solutions like that; you can get to the weirder stuff down the road if you need it (and you may never need it!)1. https://www.typescriptlang.org/docs/handbook/compiler-option...
We don't use ts-node for our dev processes because it adds some annoying startup delay. We keep the TS compiler running at all times on our dev machines, and we run our server/tests/etc. from the TS compiler's build output directory. This hasn't been a big pain point for us so I wouldn't worry about it much.
Related, just in case: I definitely wouldn't use ts-node in production. If your deployed code fails to typecheck for some reason, you don't want to learn that by seeing your backend server failing to boot in production. I think you should always compile your app during your deploy process, then have production boot the compiled JS as if TS weren't involved at all.
Perhaps others here will find it useful as well.
https://github.com/typescript-cheatsheets/react-typescript-c...
> Noticing the time when you posted your comment
Uh, I am just kind of a night owl. Most of our team members work out of Redmond, WA, and our distributed members are either on the East or West coast of the US.
Fortunately, I work as a team lead, and this was on an experimental branch, so I was able to hand off bits of code relating to architectural patterns I was evaluating to my team to continue work on those.
But I simply could not proceed with my code as is, a very frustrating experience to say the least. How is this even possible?
As a team lead, I'm sure you know...bugs happen. What sort of internal error was it causing? Something specific and spelled out, or a generic uncaught exception?
Error: Debug Failure. at Object.assertDefined (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:1690:24) at /media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:13175:89 at String.replace (<anonymous>) at formatStringFromArgs (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:13175:21) at Object.createFileDiagnostic (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:13191:20) at createDiagnosticForNodeInSourceFile (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:7770:19) at Object.createDiagnosticForNode (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:7760:16) at handleSymbolAccessibilityError (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:71556:50) at checkEntityNameVisibility (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:71929:13) at visitDeclarationSubtree (/media/psf/Code/Hypothesize/node_modules/typescript/lib/tsc.js:72066:29)