It is common in typescript to write Record<string,T>
for whatever type T
you
store in an object.
But, are you sure you're actually going to get an T
back? What if some random
user provided string is used to index the Record, and it produces undefined? You
might think, as a typescripter "do I really have to add undefined to the
signature, shouldn't Typescript check this for me"? Well..
noUncheckedIndexedAccess
tsconfig.json settingThere is actually a built-in Typescript setting called
noUncheckedIndexedAccess
This setting makes the return type of accessing any Record or Array into an
T|undefined
.
The catch?
Therefore: you really do have to ask yourself. Do you feel lucky punk? Sorry
wrong line. I mean, do you want to use a Record<string,T>
or a
Record<string,T|undefined>
?
Enjoy! https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess
Discussion on why this is not on by default: https://github.com/microsoft/TypeScript/issues/49169
noUncheckedIndexedAccess
be split into two settings?I feel like using 'untrusted input' or 'runtime values' to access a Record is
more common than using 'untrusted input' to access an array index, so it would
be sort of nice if noUncheckedIndexedAccess
was split into two separate
settings...one for Records, one for Arrays. A common complaint is that the
'array access' part of this setting is a little too strict, and requires
non-null assertions
Map
insteadThe Map::get
method returns T|undefined
, so it forces you to consider the
undefined case always. I find Maps slightly more cumbersome to use than plain
old objects, but has this benefit amongst others!
Record<string, T|undefined>
Maybe you are certain there aren't actually undefined values stored in your
object, and you just used Record<string, T|undefined>
to be able to say
obj['randomthing']
returns undefined.
Well, now calling e.g. Object.values(obj)
will return (T|undefined)[]
(similar for Object.entries
) which is slightly annoying as a user, why may
want it to just be T[]
but they can non-null assert or filter out potential
undefined's as a workaround.
Record<string, T|undefined>
If you read this article and said, ya, I'm gonna use noUncheckedIndexedAccess
in the tsconfig.json of my library, and you feel all safe and cozy using
Record<string, T>
, well your users may still have trouble: if the consumers of
your library don't use the noUncheckedIndexedAccess
tsconfig.json setting,
then they will not get the benefit of that undefined condition unless you
explicitly mark your exported types as Record<string, T|undefined>
https://cmdcolin.github.io/posts/2024-10-29-superstitionsbegone