I've noticed type guards applied to union types narrow the else branch in a potentially unsound way.
const isShortString = (value: any): value is string => {
return typeof value === 'string' && value.length < 10;
}
const fn1 = (value: string | number) => {
if (isShortString(value)) {
// ✅ Correctly narrowed to string
return value.trim();
} else {
// ❌ Incorrectly narrowed to `number` (This could still be a string with length < 10)
return value.toExponential();
}
}
TS handles it well with native type guards; or I guess more accurately when checking a "type guard" && "some other condition".
const fn2 = (value: string | number) => {
if (typeof value === 'string' && value.length < 10) {
// ✅ Correctly narrowed to `string`
return value.trim();
} else {
// ✅ Correctly remains `string | number`
return value.toExponential(); // Error
}
}
Is there a way to express that isShortString shouldn't narrow the else branch or is this a misuse of type guards?