We don't currently have any typing in our codebase.
We "support" typescript already in that in front-end and projects .ts files 'just work'.
(However, we don't currently have a tsconfig file or anything.)
While noodling around a bit I tried enabling type checking in js files (in non-strict mode) and it produced a few hundred errors.
TODO: check if there is a way to make this even more lenient?
A lot of the errors are to do with component props, i.e. typescript treats props without default values as non-optional, whereas we in js land have been treating them as optional.
I think our codebase is working well, is well structured, is low on bugs, does state management well, and we're productive working with it. It is maybe the most productive large codebase I've worked in. It's also easily comprehensible and we have no/little problem going back to something we used to work on. We've succeeded well in keeping things simple and this should always be a primary goal!
However, the lack of types has a few negatives:
Lacklustre intellisense — vscode suggestions are not optimal quality
No intellisense in projects — shipping d.ts files into <project-dir>/node_modules would give intellisense that was equivalent to working in front-end. This is the simplest way to achieve intellisense (and the only way to get the best possible intellisense)
Type weakness — I'm skeptical about the benefits of going overboard with typing, but there are a few cases where having it available is a 100% win, e.g.:
enums being fully type checked (vs named constants) (NB minor downside they are slightly larger when compiled as TS enums compile to IIFEs)
type-specific utils being restricted to valid types (e.g. path utils expecting a string vs those expected a 'Path' object etc.)
People currently frown on packages without type definitions
A large-scale switch to typescript
To actually switch everything to typescript would be a big job. (I'm including in this adding a significant/complicated type system.)
Also, we are both relative TS noobs and I think the chances are high we would end up not producing the best result at our first attempt.
I'm skeptical that switching to TS would increase our productivity. It would be a large time investment diverted away from continuing to be productive.
I'm also skeptical that it would reduce incidence of bugs. It would add a lot of LoC and in general that always increases the surface area for bugs to arise in.
JSDoc
I've been playing around with JSDoc. The duplication between code and jsdoc comments is significant — e.g.s: function params, component interfaces — and you have to keep them in sync manually unlike with ts. (Probably copilot minimises this in terms of time spent.)
It does seem promising as an easy-peasy, incremental way to add type info to existing utils without changing anything.
It seems to give less strong type assurances/hints in intellisense, e.g. I was disappointed that with a jsdoc enum:
At point of use, vscode will only tell you the type is 'string', not specifically InitState type, unlike for a ts enum. You also cannot work around this by writing:
because ts complains that in Initial: 'initial' the string 'initial' is the wrong type (?).
The API (in front-end)
API-returned objects are a potential candidate for typing as they're consumed in widespread places around the application, and good intellisense ergonomics would be valuable for working with them.
There's maybe the most scope for complexity to get out of control here, but our API is pretty simple so perhaps it can be kept minimally complicated.
Backend
I'd be very reluctant to adopt TS on the backend as it would complicate the tooling/introduce a build step.
What should we do?
Dunno, but these are my current thoughts:
Be incremental
Keep it EXTREMELY simple stupid (this above all) i.e. not write a huge complicated type system, e.g. this — 👍; this — 👎👎👎.
Simple adoption we could do:
convert named constant def .js files to enums in .ts files
add types to utils incrementally (NB: only frontend-specific ones!)
Medium level adoption we could do:
enable lenient type checking via a tsconfig file, fix a few hundred "errors"/ts incompatibilities
add interfaces for components
this would enable some semi-blocked work in tooling land, as mentioned above
consider using composed types to define some props that are commonly picked/sent down the component tree. With caution though, as this does seem like it would need some careful design work and might create brittleness in refactoring.
add types to api-client objects/funcs
Overall I think there are probably some easy wins, but unfortunately we prob need to fix the few hundred errors first off. A lot of this might be just adding default values like = null to component props.
What I'm imagining is a mix of JS and TS, with TS mostly in definition files/utils, and would diverge significantly from accepted TS best practice, with e.g. free reign to use any for convenience. Basically my thinking is to sprinkle in some TS where there are simple wins and where necessary for our developer tooling, and maybe a hybrid approach with JSDoc where that's easier and perhaps in shared utils that also need to be used by backend code.
Some thoughts
Where we are now
<project-dir>/node_modules
would give intellisense that was equivalent to working in front-end. This is the simplest way to achieve intellisense (and the only way to get the best possible intellisense)A large-scale switch to typescript
JSDoc
At point of use, vscode will only tell you the type is 'string', not specifically InitState type, unlike for a ts enum. You also cannot work around this by writing:
because ts complains that in
Initial: 'initial'
the string 'initial' is the wrong type (?).The API (in front-end)
Backend
What should we do? Dunno, but these are my current thoughts:
Overall I think there are probably some easy wins, but unfortunately we prob need to fix the few hundred errors first off. A lot of this might be just adding default values like
= null
to component props.What I'm imagining is a mix of JS and TS, with TS mostly in definition files/utils, and would diverge significantly from accepted TS best practice, with e.g. free reign to use
any
for convenience. Basically my thinking is to sprinkle in some TS where there are simple wins and where necessary for our developer tooling, and maybe a hybrid approach with JSDoc where that's easier and perhaps in shared utils that also need to be used by backend code.