1

I would like to figure out if there is a way of applying a map to a type predicate to be able to replace the repeated calls (one for each variable) in the following code snippet so that TSC (still) knows that A and B are iterables (which Sets are):

if(isSet(A) && isSet(B)) {                                                                                                     
    return isSuperSet( [...A], [...B])    
}

isSet is, of course, the type predicate:

function isSet(x:any): x is Set<unknown> { return x instanceof Set }   

I tried replacing it with something that checks that [A,B] is an array, Set<unknown>[], but that does not seem to work with this definition, as A and B loses their type inference and fall back to the "outer" looser definition.

function everyIsASet(array: any): array is Set<unknown>[] { return array.every(isSet);

error 2488 from TSC

I am a bit surprised, given that if [A,B] is an array of Set, that should imply that the individual elements would all be Sets, and that the compiler cannot pick that up/loses this in the if block.

This related question seems to imply that this is possible, but I am not seeing what I am missing.

One way of "hacking" around this is to create temporary variables like this:

const arr = [A,B]
if(isSetArray(arr)) {                                                                                                                
    const [newA, newB] = arr;                                                                                                        
    return isSuperSet( [...newA], [...newB])                                                                                         
}                        

... which works, but seems unnecessary.

oligofren
  • 20,744
  • 16
  • 93
  • 180
  • 1
    I don't think the related question implies you can narrow multiple variables, only that you can combine multiple custom type guard for a single variable – Titian Cernicova-Dragomir Jan 27 '23 at 15:09
  • Ah, was scanning a wee bit fast, perhaps. Saw mentions of type predicates, map and filter and thought Presto! – oligofren Jan 27 '23 at 15:15
  • 3
    To the best of my knowledge this is still not possible – Titian Cernicova-Dragomir Jan 27 '23 at 15:23
  • Yeah, for this to work the new information about what the array contains would need to be passed up into the outer scope's type information and affect the types of the array's constituents, and that seems quite a bit hairier than just overwriting the type in the current block. – oligofren Jan 27 '23 at 15:31

1 Answers1

1

This is unfortunately not currently possible. The only workaround I know of is the one you're using: package the values you want to guard into a single object and guard that object.

There's a longstanding open feature request at microsoft/TypeScript#26916 asking for the ability to return multiple type predicates in a single custom type guard function. It's marked as "Awaiting More Feedback" so if you want to see this happen it wouldn't hurt if you were to give it a , and leave a comment describing your use case and why the workarounds aren't sufficient. It might not help much either (lots of issues are in such a state and the TS team can't implement them all), but it wouldn't hurt.

jcalz
  • 264,269
  • 27
  • 359
  • 360