TypeScript: Strict Null Checks
Proposed change
Enable strictNullChecks
in our TypeScript configuration.
How it looks now
Our current TypeScript configuration allows us to utilise variables that may possibly be null
or undefined
, without throwing any errors or warnings.
Problem
Consider the following code as an example:
1 | const printValue = (value: number) => console.log(value)
2 | const data: number[] = [181, 191, 193, 197, 199, 211]
3 | const value = data.find(val => val === 211)
4 | printValue(value) // > 211
Now consider what might happen if our data
array will not include an expected value of 211
:
1 | const printValue = (value: number) => console.log(value)
2 | const data: number[] = []
3 | const value = data.find(val => val === 211)
4 | printValue(value) // > undefined
One might expect TypeScript to display an error on line 4 as the array will never contain a value of 211
. We currently do not see an error here as we have strictNullChecks
disabled.
With strictNullChecks
enabled, we would be alerted to the fact that 211
may never be defined:
4 | printValue(value);
// Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
// Type 'undefined' is not assignable to type 'number'. ts(2345)
Solution
After enabling strictNullChecks
, we have two potential solutions to this problem:
We can either update our function to handle undefined values...
1 | const printValue = (value: number | undefined) => {
| if (!value) console.log('No value provided.')
| else console.log(value)
| }
...or we could handle the error state outside of the Array.find()
if we know for certain that the value we're searching for should exist in our array:
3 | const value = data.find(val => val === 211)
| if (!value) throw new TypeError('211 was not found when it should exist.')
| else printValue(value)
Motivation
We might consider this change as necessary as:
-
It allows us to write safer code. We use TypeScript to be alerted to errors before they're commited to the codebase. With
strictNullChecks
disabled we're effectively allowing some errors to exist when they need not exist. -
Null pointer errors are some of the most common bugs in large codebases. This excellent feature from TypeScript largely negates them by forcing us to manage our null states.
-
In theory, this should help us discover areas in the codebase where we are failing to include loading or error states in our UI.
Proposed transition strategy
This change is likely to result in a large number of errors accross pm-netbank, but I believe strongly that we should commit to resolving this problem while it is still small enough to tackle. The longer we wait, them more complex this will be to solve.
I propose we start by adding strictNullChecks
to one app, then move onto the next, as time permits. I am happy to start with epk-flex
, which we can then use as a reference for updating the rest of the apps.
Steps
- Add
strictNullChecks: true,
to thecompilerOptions
intsconfig.json
for EPK Flex in pm-netbank. - Find all errors in the project by running
tsc --noEmit
in a terminal. This will highlight all type errors without emitting build artifacts locally. - Resolve errors that have arisen as a result of enabling
strictNullChecks
. - Open a pull request.
- Rinse & repeat until all pm-netbank apps are up to date.
- [Optional]: PM-Netbank should probably be utilising a single TypeScript configuration. When all errors are resolved, we may consider moving
tsconfig.json
to the globalpm-netbank
directory instead of maintaining a seperatetsconfig.json
in all apps.