Adding a way to handle lists of generics with unbounded size:
function identity<...T>(array: T) {
// ...
}
Which would be equivalent to:
declare function identity2<A, B>(items:[A, B]): [A, B];
declare function identity2<A, B, C>(items:[A, B, C]): [A, B, C];
// with infinitely many signatures
function identity<T>(items:T): T {
return items;
}
Test it here.
That would for example be useful to type a reverse function. That function would take an arbitrary number of arguments and return them in reverse order: reverse(1, 2, "3") = ["3", 2, 1]. For now it seems that this is only possible by having a fixed length for the input, or by declaring several signatures, one for each possible number of arguments.
A more concrete use case I have is with this zip function, which for now only takes 2, 3 or 4 iterables as parameter:
declare function zip<A, B>(Iterable<A>, Iterable<B>): Iterable<[A, B]>;
declare function zip<A, B, C>(Iterable<A>, Iterable<B>, Iterable<C>): Iterable<[A, B, C]>;
declare function zip<A, B, C, D>(Iterable<A>, Iterable<B>, Iterable<C>, Iterable<D>): Iterable<[A, B, C, D]>;
export function *zip<T>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
const iterators = iterables.map(iterable => iter(iterable));
while(true){
const items = iterators.map(iterator => iterator.next());
if (items.some(item => item.done)){
return;
}
yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
}
}
Well, I think it is!
export function *iter<T>(iterable:Iterable<T>): Iterator<T> {
yield* iterable;
}
export function *zip<T: $ReadOnlyArray<mixed>>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
const iterators = iterables.map(iterable => iter(iterable));
while(true){
const items = iterators.map(iterator => iterator.next());
if (items.some(item => item.done)){
return;
}
yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
}
}
Most helpful comment
Is this sufficient for your use case?