I found myself wrangling with what I thought was an odd TS issue yesterday afternoon. During a quick chat about it, my boss gave me this gem of an example and I had to share it.
What's the difference between?
someString && obj[someString] ? [obj[someString]] : []
and
const specificVal = someString && obj[someString];
const result = specificVal ? [specificVal] : [];
To break down the first statement, we're saying
- If
someString
is truthy (notnull
orundefined
etc.) andobj
has a keysomeString
, the ternary should return an array that holds the value ofsomeString
. - If the conditional is falsy, an empty array is returned.
The second statement breaks this into two steps, first by defining specificVal
, and then using a ternary to return an array with that value or an empty array.
Just looking at them, they're pretty similar statements, so what's the difference between them?
A whole lot. It might manifest itself as a TypeScript issue, but it's there for a reason.
Typescript can't infer and guarantee that obj[someString]
in the conditional statement is going to be the same as obj[someString]
in the return statement, so we split it in to two variables.
Here's a fun example of that - Proxies make objects that on access, can run code to return a result!
const map = new Proxy({}, {get(target, prop, receiver) {return Math.random(); }})
Consider doing something like:
const value = map[1] > 0.5 ? map[1] : 0
This won't be consistent with returning something higher than 0.5 or 0.
Splitting it up now fixes that problem.
const v = map[1]
if v > 0.5 ? v : 0
Essentially object and array access can be just as dynamic as functions (via Proxies, getters and other traps) and we need to treat them as such in places to make TypeScript happy.
Shoutout (and all credit) to James Canning for the example and explanation!
Top comments (0)