ben szabo

The road to `strict` TypeScript

A practical guide on how we are gradually progressing towards strictly typed (and null-checked) code.

stack of books

It's been almost two years since I've joined Lottie on her mission, to elevate later life. If you'd think that being in the business for eldercare is slow, you'd be rather wrong.

Need for speed

Working at a startup is quite the experience. Ideating, creating, validating, iterating at a very fast pace.

Developing shiny new things and delivering them into the hands of hundreds of people is rewarding and fun.

What isn't fun is delivering bugs. In order to keep the bugs at bay, we use TypeScript, so we thought we were good.

We were fast and fur oblivious to the fact that when our project got configured, a tiny but important option has been missed.

Our tsconfig was missing strict: true;. And strict null checks too. $#!+.

Wait a minute, why is this a problem?

I hear you ask, rightfully so. The code builds, we don't have that many problems, should we even bother? We can just build new stuff instead and fix the bugs.

Whilst the above is true, to a degree, we identified some key problems.

For example after fetching data from APIs, we were getting random runtime errors due to data integrity issues. As an obvious solution to the problem, we opted to use Zod to parse our data and get types as a bonus, however, we were left with optional everything, as Zod requires strict mode.

Getting back on track

I've noticed this a while ago, but when I naively turned on strict mode and ran a type check I've been greeted with a ton of errors. About 1100.

This got me thinking. There is no way we can or should do a refactor of this magnitude, so on my next "hack day" – Lottie Engineering's bi-weekly learning and development day – I set out to do some research and come up with a plan for this.

Thankfully I bumped into an article on the VS Code blog about gradually enabling strictNullChecks for their project. So taking their idea, I played around to see if the same can be done for enabling `strict` mode too. The answer is yes.

At the time of writing, we still have 760 Errors to tackle, but at least we have a way to deal with them.

The setup

I've created a secondary config file, called tsconfig.strictFlag.json where I've extended our base tsconfig.json, than added some explicit include/exclude properties.

{
"extends": "./tsconfig.json", // our main config
"compilerOptions": {
  "noEmit": true, // Don't output any javascript
  "strict": true, // enable `strict` mode
  "strictNullChecks": true // enable strict null checks
},
"exclude": [
  "node_modules",
  
  // PLEASE DELETE FILES AS YOU MAKE THEM STRICT
 
  // APP
  "app/location/**/*",
 
  // COMPONENTS
  "components/Wizard/**/*",
 
  // DATA
  "data/wizard/**/*",
 
  // LIB
  "lib/content/**/*",
 
  // PAGES API
  "pages/api/**/*"
],
"include": [
  // See above for excludes!
  "app/**/*",
  "components/**/*",
  "data/**/*",
  "lib/**/*",
  "pages/**/*"
]
}
 

Once I was happy with this, I configured two scripts in our package.json. The first one served as a type check, ran via a pre commit hook, and the other as a helper whilst developing, as the IDE would rely on the main config file.

{
"strict-typecheck": "npx tsc -p ./tsconfig.strictFlag.json",
"strict-typecheck:watch": "npm run strict-typecheck -- --watch"
}

---

Photo by Judith Frietsch on Unsplash