You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When I have a conditional that narrows a type in the TRUE branch but does not narrow in the FALSE branch, I have no way to extract the condition into a function and preserve the narrowing. That is, I have an implication of the form a => b without !a => !b. Existing type predicates require a <=> b.
The existing type predicate functionality doesn't help me because the compiler assumes they can be inverted. I have no way to narrow the type only if my predicate returns true, but do no narrowing when it returns false.
π Motivating Example
functioninterestingDifferenceInline(x?: number,y?: number){if(x!==undefined&&x>12&&y!==undefined&&y>12){// x and y correctly have type number here, undefined narrowed away.// however, my logic is duplicated.returnx-y;}else{// x and y are not narrowed here, still have type undefined | number.returnundefined;}}// I should be able to extract the duplicated logic into a function// and get the same type narrowingfunctioninterestingDifferenceExtracted(x?: number,y?: number){if(isInteresting(x)&&isInteresting(y)){// TYPE ERROR: x and y should have type number here, but have number | undefined.returnx-y;}else{returnundefined;}}functionisInteresting(x: number|undefined): boolean{// if this function returns true, x should be narrowed to number,// if this function returns false, it should not be narrowed at all.// We have implication in one direction, but not its inverse.returnx!==undefined&&x>12;}// this is wrong:functionisInterestingIncorrectPredicate(x?: number): x is number{// this correctly narrows to number if we do if(isInterestingIncorrectPredicate(x)),// but incorrectly narrows to undefined if we do if(!isInterestingIncorrectPredicate(x))// type predicates are 'necessary and sufficient', but our condition is// 'sufficient but not necessary'. That is, we don't know that x is NOT a// number if this predicate returns false.returnx!==undefined&&x>12;}// what we want is some kind of inverse predicate, something like:// returning true gives us type information, returning false does not.// function isInterestingDesired(x?: number): x is not undefined {// if this function returns true x is narrowed to number, excluding undefined.// if this function returns false nothing is narrowed.// }
π» Use Cases
I want to improve my code quality by extracting complex, duplicated code into a function without losing type information.
The text was updated successfully, but these errors were encountered:
gavinwahl
changed the title
Type predicates that are sufficient but not necessary
Type predicates that are not biconditional
May 20, 2025
π Search Terms
predicate narrowing
β Viability Checklist
β Suggestion
When I have a conditional that narrows a type in the TRUE branch but does not narrow in the FALSE branch, I have no way to extract the condition into a function and preserve the narrowing. That is, I have an implication of the form
a => b
without!a => !b
. Existing type predicates requirea <=> b
.The existing type predicate functionality doesn't help me because the compiler assumes they can be inverted. I have no way to narrow the type only if my predicate returns true, but do no narrowing when it returns false.
π Motivating Example
π» Use Cases
I want to improve my code quality by extracting complex, duplicated code into a function without losing type information.
The text was updated successfully, but these errors were encountered: