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
A way to make Array.every refine the type of the argument array. This isn't sound, but I think the unsoundness is similar in spirit TypeScript's usual unsoundness around mutability.
functionmax1<T>(stuff: Array<string|number>): number{if(stuff.every(x=>typeofx==='number')){Math.max(...stuff);// Error: 'string | number' is not assignable to 'number'.}return-1;}
I tested it out with my own every function. But to get my original example to work, I needed to annotate the return type of my predicate:
declarefunctionevery<T,RextendsT>(array: Array<T>,predicate: (value: T)=>value is R): array is Array<R>;functionmax2<T>(stuff: Array<string|number>): number{if(every(stuff,x=>typeofx==='number')){// Error: (x: string | number) => boolean' is not assignable to '(value: string | number) => value is string | number'Math.max(...stuff);}return-1;}// Works with explicit type annotation on predicate return type.functionmax3<T>(stuff: Array<string|number>): number{if(every(stuff,(x): x is number=>typeofx==='number')){Math.max(...stuff);}return-1;}
π» Use Cases
The original inspiration for this line of thought came from writing a zip-style function:
function*zip<T>(...iterables: Array<Iterable<T>>): Iterable<Array<T>>{if(iterables.length===0)thrownewError('iterables is empty');// Explicit annotation on 'iterators' because Iterator's second type argument defaults to 'any', which masks the 'r.value' error below.constiterators: Array<Iterator<T,unknown,never>>=iterables.map(it=>it[Symbol.iterator]());while(true){constresults=iterators.map(it=>it.next());if(!every(results,r=>r.done!==true)){// Error here, but I don't know what annotation to write.return;}yieldresults.map(r=>r.value);// Error here, because r.value might be for a 'done' iterator}}
The text was updated successfully, but these errors were encountered:
In order for every() to narrow the type you must pass in a type guard function. You currently don't do that, but if you would it would work as you expect.
This is not a type guard: x => typeof x === 'number'
This is a type guard: (x): x is number => typeof x === 'number'
@MartinJohns's original comment had some additional information that was helpful to me:
In order for every() to narrow the type you must pass in a type guard function. You currently don't do that, but if you would it would work as you expect.
This is not a type guard: x => typeof x === 'number'
This is a type guard: (x): x is number => typeof x === 'number'
I removed that part of the comment because you actually mentioned those parts in your issue already. :-) Or so I thought, re-reading your issue I think I too hastely removed that comment.
Suggestion
π Search Terms
array refine every
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
A way to make
Array.every
refine the type of the argument array. This isn't sound, but I think the unsoundness is similar in spirit TypeScript's usual unsoundness around mutability.π Motivating Example
Playground link
It would be nice if this worked:
I tested it out with my own
every
function. But to get my original example to work, I needed to annotate the return type of my predicate:π» Use Cases
The original inspiration for this line of thought came from writing a
zip
-style function:The text was updated successfully, but these errors were encountered: