Skip to content

Commit

Permalink
Merge pull request #157 from MattiasBuelens/improve-abortsignal-type
Browse files Browse the repository at this point in the history
Improve type of `WritableStreamDefaultController.signal`
  • Loading branch information
MattiasBuelens authored Jan 5, 2025
2 parents c2f7590 + 82f3bb2 commit 05e8383
Show file tree
Hide file tree
Showing 13 changed files with 45 additions and 56 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* The `next()` and `return()` methods of `ReadableStream`'s async iterator are now correctly "chained",
such that the promises returned by *either* of these methods are always resolved in the same order
as those methods were called.
* 💅 Improve type of `WritableStreamDefaultController.signal`. ([#157](https://github.com/MattiasBuelens/web-streams-polyfill/pull/157))

## 4.0.0 (2024-02-28)

Expand Down
12 changes: 8 additions & 4 deletions etc/web-streams-polyfill.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@
```ts

// @public
export interface AbortSignal {
readonly aborted: boolean;
addEventListener(type: 'abort', listener: () => void): void;
export type AbortSignal = typeof globalThis extends {
AbortSignal: {
prototype: infer T;
};
} ? T : {
aborted: boolean;
readonly reason?: any;
addEventListener(type: 'abort', listener: () => void): void;
removeEventListener(type: 'abort', listener: () => void): void;
}
};

// @public
export class ByteLengthQueuingStrategy implements QueuingStrategy<ArrayBufferView> {
Expand Down
6 changes: 6 additions & 0 deletions src/globals.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
/// <reference lib="dom" />

declare global {
// From @types/node
// eslint-disable-next-line no-var
var global: typeof globalThis;
}

function getGlobals(): typeof globalThis | undefined {
if (typeof globalThis !== 'undefined') {
return globalThis;
Expand Down
46 changes: 11 additions & 35 deletions src/lib/abort-signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,16 @@
* via its associated `AbortController` object.
*
* @remarks
* This interface is compatible with the `AbortSignal` interface defined in TypeScript's DOM types.
* It is redefined here, so it can be polyfilled without a DOM, for example with
* {@link https://www.npmjs.com/package/abortcontroller-polyfill | abortcontroller-polyfill} in a Node environment.
* This is equivalent to the `AbortSignal` interface defined in TypeScript's DOM types or `@types/node`.
*
* @public
*/
export interface AbortSignal {
/**
* Whether the request is aborted.
*/
readonly aborted: boolean;

/**
* If aborted, returns the reason for aborting.
*/
export type AbortSignal = typeof globalThis extends { AbortSignal: { prototype: infer T } } ? T : {
aborted: boolean;
readonly reason?: any;

/**
* Add an event listener to be triggered when this signal becomes aborted.
*/
addEventListener(type: 'abort', listener: () => void): void;

/**
* Remove an event listener that was previously added with {@link AbortSignal.addEventListener}.
*/
removeEventListener(type: 'abort', listener: () => void): void;
}
};

export function isAbortSignal(value: unknown): value is AbortSignal {
if (typeof value !== 'object' || value === null) {
Expand All @@ -47,32 +30,25 @@ export function isAbortSignal(value: unknown): value is AbortSignal {
* A controller object that allows you to abort an `AbortSignal` when desired.
*
* @remarks
* This interface is compatible with the `AbortController` interface defined in TypeScript's DOM types.
* It is redefined here, so it can be polyfilled without a DOM, for example with
* {@link https://www.npmjs.com/package/abortcontroller-polyfill | abortcontroller-polyfill} in a Node environment.
* This is equivalent to the `AbortController` interface defined in TypeScript's DOM types or `@types/node`.
*
* @internal
*/
export interface AbortController {
// Trick with globalThis inspired by @types/node
// https://github.com/DefinitelyTyped/DefinitelyTyped/blob/0c370ead967cb97b1758d8fa15d09011fb3f58ea/types/node/globals.d.ts#L226
export type AbortController = typeof globalThis extends { AbortController: { prototype: infer T } } ? T : {
readonly signal: AbortSignal;

abort(reason?: any): void;
}

interface AbortControllerConstructor {
new(): AbortController;
}

const supportsAbortController = typeof (AbortController as any) === 'function';
};

/**
* Construct a new AbortController, if supported by the platform.
*
* @internal
*/
export function createAbortController(): AbortController | undefined {
if (supportsAbortController) {
return new (AbortController as AbortControllerConstructor)();
if (typeof AbortController === 'function') {
return new AbortController();
}
return undefined;
}
2 changes: 0 additions & 2 deletions src/lib/readable-stream/async-iterator.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/// <reference lib="es2018.asynciterable" />

import { ReadableStream } from '../readable-stream';
import {
AcquireReadableStreamDefaultReader,
Expand Down
9 changes: 8 additions & 1 deletion src/stub/dom-exception.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
/// <reference types="node" />
import { globals } from '../globals';
import { setFunctionName } from '../lib/helpers/miscellaneous';

declare global {
interface ErrorConstructor {
// From @types/node
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
captureStackTrace(targetObject: object, constructorOpt?: Function): void;
}
}

interface DOMException extends Error {
name: string;
message: string;
Expand Down
2 changes: 0 additions & 2 deletions src/stub/math-trunc.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/// <reference lib="es2015.core" />

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc#Polyfill
const MathTrunc: typeof Math.trunc = Math.trunc || function (v) {
return v < 0 ? Math.ceil(v) : Math.floor(v);
Expand Down
2 changes: 0 additions & 2 deletions src/stub/number-isfinite.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/// <reference lib="es2015.core" />

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite#Polyfill
const NumberIsFinite: typeof Number.isFinite = Number.isFinite || function (x) {
return typeof x === 'number' && isFinite(x);
Expand Down
2 changes: 0 additions & 2 deletions src/stub/number-isinteger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/// <reference lib="es2015.core" />

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger#Polyfill
const NumberIsInteger: typeof Number.isInteger = Number.isInteger || function (value) {
return typeof value === 'number'
Expand Down
2 changes: 0 additions & 2 deletions src/stub/number-isnan.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/// <reference lib="es2015.core" />

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN#Polyfill
const NumberIsNaN: typeof Number.isNaN = Number.isNaN || function (x) {
// eslint-disable-next-line no-self-compare
Expand Down
2 changes: 0 additions & 2 deletions src/stub/symbol.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
/// <reference lib="es2015.symbol" />

const SymbolPolyfill: (description?: string) => symbol
= typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol'
? Symbol
Expand Down
13 changes: 9 additions & 4 deletions test/types/writable-stream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,14 @@ const closePromise: Promise<void> = writableStream.close();
const abortPromise: Promise<void> = writableStream.abort('aborted');

// Compatibility with stream types from DOM
// FIXME Remove deprecated WritableStreamDefaultController.abortReason
// FIXME Align our AbortSignal definition with TypeScript's version
// const domUnderlyingSink: UnderlyingSink<string> = underlyingSink;
declare global {
interface WritableStreamDefaultController {
// FIXME Remove deprecated WritableStreamDefaultController.abortReason
abortReason: any;
}
}

const domUnderlyingSink: UnderlyingSink<string> = underlyingSink;
const domWritableStream: WritableStream<string> = writableStream;
// const domController: WritableStreamDefaultController = controller;
const domController: WritableStreamDefaultController = controller;
const domWriter: WritableStreamDefaultWriter<string> = writer;
2 changes: 2 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
"moduleResolution": "node",
"lib": [
"es5",
"es2015.core",
"es2015.promise",
"es2015.symbol",
"es2015.symbol.wellknown",
"es2018.asynciterable"
],
"newLine": "lf",
Expand Down

0 comments on commit 05e8383

Please sign in to comment.