microsoft / TypeScript-DOM-lib-generator

Tool for generating dom related TypeScript and JavaScript library files
Apache License 2.0
616 stars 417 forks source link

Make the chunk parameter of ReadableStreamDefaultController.enqueue non optional #1682

Open PeterD1524 opened 8 months ago

PeterD1524 commented 8 months ago

The Web IDL definition specifies an enqueue method for the ReadableStreamDefaultController class with the following signature:

undefined enqueue(optional any chunk);

The chunk parameter is optional which probably is fine since chunk is any.

However, this is a little problematic with TypeScript generics. Currently, the generated TypeScript interface looks like this:

interface ReadableStreamDefaultController<R = any> {
    enqueue(chunk?: R): void;
}

This allows undefined to be enqueued into the stream while the reader of the stream still expects to read R out of it.

This is demonstrated in the following example:

const stream = new ReadableStream<string>({
  start: (controller) => {
    // currently the signature is
    // ReadableStreamDefaultController<string>.enqueue(chunk?: string | undefined): void
    // undefined is enqueued here
    controller.enqueue();
  },
});

// ReadableStreamDefaultReader<string>
const reader = stream.getReader();

// ReadableStreamReadResult<string>
const result = await reader.read();
if (result.done === false) {
  // result is narrowed down to ReadableStreamReadValueResult<string>

  // TypeScript assumes ReadableStreamReadValueResult<string>.value is string
  // so the compilation will succeed
  // but result.value is actually undefined
  result.value.toUpperCase();
}

To address this, could we consider overriding the chunk parameter to be required? There are similar issues with TransformStreamDefaultController.enqueue and WritableStreamDefaultWriter.write.