`consume` types and `AnyIterable`

Open
#232 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Stale
Tech stack
typescript
Domain
api

Research direction

Start at the consume overload declarations and implementation shown in the issue, then reproduce the TypeScript errors using the AnyIterable examples. Check how the overloads handle both Iterable and AsyncIterable inputs and verify that calls with either source type resolve to an appropriate return type.

Written by the indexing model from the issue text.

Description

It doesn't look like I can use the AnyIterable type with consume, even though it supports both Iterable<T> and AsyncIterable<T> as input:

import { consume } from 'streaming-iterables'
import type { AnyIterable } from 'streaming-iterables'

// specify return type otherwise typescript works out this is really `number[]`
function createSyncSource (): AnyIterable<number> {
  return [1, 2, 3]
}

// specify return type otherwise typescript works out this is really `AsyncGenerator<number, void, undefined>`
async function * createAsyncSource (): AnyIterable<number> {
  yield * [1, 2, 3]
}
const sourceArr = createSyncSource()
const sourceGen = createAsyncSource()

// works if I cast to the underlying type
consume(sourceArr as number[])
consume(sourceGen as AsyncIterable<number>)

// does not select the correct overload based on the possible types of input
consume(sourceArr)
consume(sourceGen)

The error is:

error TS2769: No overload matches this call.
Overload 1 of 2, '(iterable: Iterable<number>): void', gave the following error.
  Argument of type 'AsyncIterable<number>' is not assignable to parameter of type 'Iterable<number>'.
    Property '[Symbol.iterator]' is missing in type 'AsyncIterable<number>' but required in type 'Iterable<number>'.
Overload 2 of 2, '(iterable: AsyncIterable<number>): Promise<void>', gave the following error.
  Argument of type 'AsyncIterable<number>' is not assignable to parameter of type 'AsyncIterable<number>'.
    Property '[Symbol.asyncIterator]' is missing in type 'Iterable<number>' but required in type 'AsyncIterable<number>'.

If I add an additional overload to the type definition that's the same as the actual implementation it starts to work:

export function consume<T>(iterable: Iterable<T>): void
export function consume<T>(iterable: AsyncIterable<T>): Promise<void>
export function consume<T>(iterable: AnyIterable<T>): Promise<void> | void // <-- new overload
export function consume<T>(iterable: AnyIterable<T>) {
  if (iterable[Symbol.asyncIterator]) {
    return _consume(iterable)
  }
  for (const val of iterable as Iterable<T>) {
    // do nothing
  }
}

But then the return type is Promise<void> | <void>. I tried doing something clever like:

export declare type UnwrapToVoidOrVoidPromise<M extends AnyIterable<any>> = M extends Iterable<any> ? void : M extends AsyncIterable<any> ? Promise<void> : never;

but it's still Promise<void> | <void>. Maybe that's ok, I'm not sure.

Dominant language
TypeScript
Stars
87
Forks
6
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from reconbot/streaming-iterables

All issues in reconbot/streaming-iterables

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.