With Typescript 3.7 the nullish coalescing operator was introduced. It would seem to be the perfect type guard for cases like
const fs = (s: string) => s
const fn = (n: number) => n
let a: string | null | undefined
let b: number | null | undefined
const x = (a ?? null) && fs(a)
const y = (b ?? null) && fn(b)
But if you put that code into typescript playground, it alerts you on both a an b params passed to fs / fn functions like:
I experimented a bit further and found it is not only an issue isolated to the nullish coalescing operator, but couldn't bend my mind around when typescript is able to use soemthing as a typeguard and when not (below you find some examples)
The two last line were confusing me most. It seems to me both expressions that are assigned to x7 and x8 would be completely equivalent but while in the expression assigned to x8 the typeguard works, it doesn't seem to be ok for typescript in the x7 expression:
const fs = (str: string) => str
const create = (s: string) => s === 's' ? 'string' : s === 'n' ? null : undefined
const a: string | null | undefined = create('s')
const b: string | null | undefined = 's'
let x
if (a !== null && a !== undefined) {
x = a
} else {
x = fs(a)
}
const x1 = a !== null && a !== undefined && fs(a)
const x2 = a !== null && a !== void 0 && fs(a)
const x3 = (a ?? null) && fs(a)
const x4 = (b ?? null) && fs(b)
const x5 = a !== null && a !== undefined ? a : fs(a)
const something = a !== null && a !== undefined
const x6 = something ? a : fs(a)
const x7 = something && fs(a)
const x8 = (a !== null && a !== undefined) && fs(a)
I'm not sure, if typescript is just incapable to apply the type guard for some reason or if it is acually a bug in typescript. So is there kind of a rulebook when typescript can apply a typeguard and when not? Or is it maybe a bug? Or is there some other reason I don't get those examples to compile?
Btw. when using a user-defined type guard of course that works perfectly, but it would be nice not to have to add some runtime code for the typeguard to work.
??
in your examples.a ?? null
is justa
in every case excepta === undefined
, in which case it'snull
. – Bondage(a ?? null) && fs(a)
to mean "null
ifa
is nullish, orfs(a)
otherwise", well, that's not what it means. – Bondage?? fs(a)
is even wronger, because thenfs(a)
is only evaluated ifa
is null or undefined. – Bondage(a ?? null) && fs(a)
is "common" enough. Still looking for an "official" answer though – Koch