I’m trying to narrow an optional argument in short-circuit evaluation.
Here’s a Typescript playground with the below code: https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABFApgZygCgA5zWmAIwBsBPAVTABMVgYwUqB+ALkQwCd6BzASkQDeAWABQiRAHoJiAO4ALFEghwQxKogAGufETKUadBlQ2IEyBYi7c5URHICG1djBqJCKROAP1GTUeI4UKBAOJAAhODhiFEccPAISCmpaHyp+ADJ0xG0EvWTDRgA6aLBuKDkAblEAXyA
function test(possiblyUndefined?: string) {
// when could `possiblyUndefined` on the right hand side be undefined?
return Boolean(possiblyUndefined) && possiblyUndefined.length;
}
This errors out with: 'possiblyUndefined' is possibly 'undefined'.
…But that can’t be right. The left-hand side of the statement can only ever succeed when possiblyUndefined
is not undefined, right?
>Solution :
Because the Boolean
function will happily accept undefined
, and TypeScript doesn’t have it defined as a type predicate that guarantees its input isn’t undefined
(probably because that’s not its purpose, even though it’s true that Boolean
will return false
for undefined
). If you look at the current definition of it, it’s this (relevant portion highlighted):
interface BooleanConstructor {
new(value?: any): Boolean;
<T>(value?: T): boolean; // <====
readonly prototype: Boolean;
}
declare var Boolean: BooleanConstructor;
That’s just a function that returns boolean
, not a type predicate.¹
If you want to handle undefined
, you can do so explicitly. I’d also use > 0
so your function always returns boolean
, not false | number
(though that’s up to you, of course):
return typeof possiblyUndefined !== "undefined" && possiblyUndefined.length > 0;
// or
return possiblyUndefined !== undefined && possiblyUndefined.length > 0;
Although these days I think I’d probably go for optional chaining (?.
) and nullish coalescing (??
):
return possiblyUndefined?.length ?? 0 > 0;
¹ It’s interesting to see from the link in Leland’s own answer that there’s at least talk of making it a predicate function. But it isn’t one as of this writing. It’s just a conversion function.