Hacker News new | ask | show | jobs
by Agent766 2198 days ago
My team started development of a React SPA. It was initially written with jsx. As we're starting to implement more, I'm finding more and more cases where the js code was wrong; property names that don't exist, wrong types being passed around, and non-existent props being used.

How do you suggest addressing this in a 10 dev team when developing in js?

7 comments

You should absolutely use TypeScript for this. This is exactly what TS is for, to assert your types (proptypes, interfaces, classes, etc.) Switch to .tsx files too. There's a bit of a learning curve for TS, but it's well worth it. You should also type your global store (whether it's in react or redux), your dispatchers, and your action creators. And if you're doing redux, consider redux-toolkit. Turn off implicit any, assert types on everything you can, don't use !, learn about union types.

Hit me up in the e-mail in my profile if you want to discuss this further, would be happy to help and discuss my reasoning further. I've been doing a LOT of TS code recently on all the major target platforms for React - browser, electron, and react-native. I manage a team who's built several applications now and we use TS for everything, including an automatically-generated TS api interface that exposes types from our C# REST backend using swagger directly to the client code.

As someone who's recently jumped into a TS codebase after using just JS for years, a blog post or resource with these tips would be very nice (even though some are obvious, a lot of people don't know they exist. Disabling implicit any was a PITA/huge help for me.) Do you say don't use ! because you can't make just anything truthy in TS, or is there another reason?
He's referring to https://www.typescriptlang.org/docs/handbook/release-notes/t... rather than boolean coercion.
Check out https://reasonml.org - created by Jordan Walke, the creator of React. Reason offers the best of both worlds - type safety without getting in the way and faster JS than what you'd write by hand.
As much as I would shill reasonml. Think before you adopt - it still requires more upfront work than typescript (you will have to write bindings for most things even popular stuff. You might end up fighting it too.) but as parent said, you get more expressiveness (algebraic types, powerful pattern matching, immutability, partial application etc) and sound type system with a speedup on both transpile times and actual run time.

You can leverage ocaml/ml as well as js ecosystem. Mix different files and syntax.

Bsb is also faster than tsc.

To add to this, there are at least 3-4 pain points which... are just a pain with ReasonML, that can kinda counteract its type system.

- non-standard ordering of arguments between belt/standard library

- Ocaml's standard library actually generally avoiding the Option/Result type, in preference of exceptions, which is unexpected and a pain since it's an ML.

- package management involves manually adding things to the bsconfig (has this changed?)

- things randomly break between relatively minor Bucklescript versions, they broke something pretty important in like a .x release when I was messing around with it

- server side isn't good. It technically works but all the bindings are old or terribly documented, and you never really know if it's not going to blow up at some point.

Otherwise, I actually quite like it! None of those are actual core language complaints.

The way it deals with async/await also seems pretty tedious.
Slightly off topic but has anyone tried Hegel? https://github.com/JSMonk/hegel, looks like a nice mix of reason,ts and flow. It's just Js with types + type inference.
These issues seem to be a symptom of bad/inexperienced developers rather than the tooling. Proptypes and linting may also help with some of your type/prop issues but competency will trump tooling most times.
I can make them use typescript more easily than I can make them good developers, I guess ...
Enforce shared ESLint rules on commit, and use Airbnb+React with most of the defaults set.
a sufficiently complex linting process is a transpiled language, with the same downsides
I would advocate for as much simplicity as possible then. :)
How would that catch a misspelled prop name?
You would end up defining PropTypes, and ESLint is capable of keeping you in check there.

It's much worse than just using TypeScript (only at runtime, PropTypes aren't that useful anywhere else, PropType syntax doesn't match Flow, TS, or jsdoc, ESLint can't check any PropTypes you spread in), but it can get you by in a pinch.

linting wouldn't, but if you're writing unit tests, that kind of problem would be caught pretty quickly.
This also works in TypeScript's favor. Meaning you can skip writing tests that simply check you're giving the correct props.
I don't think anyone /does/ write tests that simply check they're giving the correct props. They write unit tests, and props are part of that.
This also works in TypeScript's favor. You get test coverage which you would never write. A "simple" component that doesn't have any logic and doesn't warrant a test still checks its prop types, and you don't have to do anything other than make the compiler pass.
I think most of this can be solved by proptypes, although true proptypes is not as thorough as TypeScript.

I had some negative experiences with typescript in a large React project but in that case the most negative experience was that often the type definitions provided by React and common type libraries didn't match our needs, which made doing something that would normally be quick difficult and long.

The reason for types not matching was often that we needed to generate HTML emails as part of things, which means you need a lot of deprecated attributes, so probably you won't have this problem.

Instead of writing types, you write tests.
You need rigorous tests though. At some point you end up with a hacked on version of typing. I appreciate that Typescript will tell me "this value might be null, and that function doesn't handle null" rather than writing a bunch of runtime checks to make sure the value isn't something invalid, and then writing tests to make sure those work.
You need rigorous tests anyway. Typescript is checking types only at compile time if I'm not mistaken and what it detects is only a set of problems. Yes it's nice that you can detect some types errors thanks to typescript, but is the development overhead worth it? With eslint, sonarqube, and tests, I think typescript is not that useful and annoying to use.

For example I contributed to Typescript's definitely typed project in the past. To make typescript more useful. But I ended up spending so much time writing type definitions. After all, I rather have some NaN or "undefined is not a function" exceptions during development.

You need less tests in a type safe language. Especially in a good one like reason / scala.js / elm. Typescript is just not very safe, its type system is unsound by design because compatibility with JS is their #1 priority.
Yes, you have the illusion of type safety but all you need is a slightly different JSON from an API to realize that typescript isn't that interesting.
All you need is a bug in your tests or mocks or fixtures to realize that tests aren't 100% foolproof either. Nothing is, we all know that.

That said, in proper type safe development at least your own API comms should be type safe. It's easy if you use the same language on client and backend, which is possible with Typescript, Reason/Ocaml, Scala, Rust, etc.

The problem with Typescript is that it's half assing type safety in the language itself and people generally half ass type safety in other aspects of development too. You just can't expect to reap the benefits of real type safety with such an approach.

That’s where you use something like https://github.com/gcanti/io-ts to enforce types on unknown data at runtime.
TypeScript is better at documenting intent for other developers (where "other developers" includes your future self) than either tests or comments/readmes. It just about entirely takes care of the "what" so comments and docs can be reserved for the "why". It's an outstanding communication tool and recording what it does, at function/method boundaries at least, is something you should be doing anyway, so might as well let a machine verify you've gotten it right.
There are libraries that will help you do runtime checks to ensure that your JSON matches the shape of your schema. It’s a bit tedious, but it works.
Eslint + a rule for propTypes. Simple!