From 7db2e4bc5bf59969490deeb00e00fa76a3d0529f Mon Sep 17 00:00:00 2001 From: Lee Byron Date: Wed, 26 May 2021 16:45:47 -0700 Subject: [PATCH] TS: Fix strict issues in src/subscription --- .../__tests__/mapAsyncIterator-test.ts | 18 +++++++++++------- src/subscription/__tests__/simplePubSub.ts | 14 ++++++++++---- src/subscription/__tests__/subscribe-test.ts | 11 +++++++---- src/subscription/mapAsyncIterator.ts | 4 ++-- src/subscription/subscribe.ts | 5 ++--- 5 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/subscription/__tests__/mapAsyncIterator-test.ts b/src/subscription/__tests__/mapAsyncIterator-test.ts index e5e374e2567..3378b00891f 100644 --- a/src/subscription/__tests__/mapAsyncIterator-test.ts +++ b/src/subscription/__tests__/mapAsyncIterator-test.ts @@ -33,7 +33,9 @@ describe('mapAsyncIterator', () => { next(): Promise> { if (items.length > 0) { - return Promise.resolve({ done: false, value: items.shift() }); + const value = items[0]; + items.shift(); + return Promise.resolve({ done: false, value }); } return Promise.resolve({ done: true, value: undefined }); @@ -105,8 +107,7 @@ describe('mapAsyncIterator', () => { expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); // Early return - // @ts-expect-error FIXME: TS Conversion - expect(await doubles.return()).to.deep.equal({ + expect(await doubles.return('')).to.deep.equal({ value: 'The End', done: true, }); @@ -130,9 +131,11 @@ describe('mapAsyncIterator', () => { return this; }, next() { + const value = items[0]; + items.shift(); return Promise.resolve({ done: items.length === 0, - value: items.shift(), + value, }); }, }; @@ -143,8 +146,7 @@ describe('mapAsyncIterator', () => { expect(await doubles.next()).to.deep.equal({ value: 4, done: false }); // Early return - // @ts-expect-error FIXME: TS Conversion - expect(await doubles.return()).to.deep.equal({ + expect(await doubles.return(0)).to.deep.equal({ value: undefined, done: true, }); @@ -194,9 +196,11 @@ describe('mapAsyncIterator', () => { return this; }, next() { + const value = items[0]; + items.shift(); return Promise.resolve({ done: items.length === 0, - value: items.shift(), + value, }); }, }; diff --git a/src/subscription/__tests__/simplePubSub.ts b/src/subscription/__tests__/simplePubSub.ts index e4d3c5569ad..7efdf40e573 100644 --- a/src/subscription/__tests__/simplePubSub.ts +++ b/src/subscription/__tests__/simplePubSub.ts @@ -1,3 +1,5 @@ +import { invariant } from '../../jsutils/invariant'; + /** * Create an AsyncIterator from an EventEmitter. Useful for mocking a * PubSub system for tests. @@ -18,7 +20,7 @@ export class SimplePubSub { getSubscriber(transform: (value: T) => R): AsyncGenerator { const pullQueue: Array<(result: IteratorResult) => void> = []; - const pushQueue = []; + const pushQueue: Array = []; let listening = true; this._subscribers.add(pushValue); @@ -33,13 +35,15 @@ export class SimplePubSub { }; return { - next() { + next(): Promise> { if (!listening) { return Promise.resolve({ value: undefined, done: true }); } if (pushQueue.length > 0) { - return Promise.resolve({ value: pushQueue.shift(), done: false }); + const value = pushQueue[0]; + pushQueue.shift(); + return Promise.resolve({ value, done: false }); } return new Promise((resolve) => pullQueue.push(resolve)); }, @@ -59,7 +63,9 @@ export class SimplePubSub { function pushValue(event: T): void { const value: R = transform(event); if (pullQueue.length > 0) { - pullQueue.shift()({ value, done: false }); + const receiver = pullQueue.shift(); + invariant(receiver); + receiver({ value, done: false }); } else { pushQueue.push(value); } diff --git a/src/subscription/__tests__/subscribe-test.ts b/src/subscription/__tests__/subscribe-test.ts index 85a0a7e5742..dcb02e042cb 100644 --- a/src/subscription/__tests__/subscribe-test.ts +++ b/src/subscription/__tests__/subscribe-test.ts @@ -42,7 +42,8 @@ const InboxType = new GraphQLObjectType({ }, unread: { type: GraphQLInt, - resolve: (inbox) => inbox.emails.filter((email) => email.unread).length, + resolve: (inbox) => + inbox.emails.filter((email: any) => email.unread).length, }, emails: { type: new GraphQLList(EmailType) }, }, @@ -103,7 +104,7 @@ function createSubscription(pubsub: SimplePubSub) { }, ]; - const data = { + const data: any = { inbox: { emails }, // FIXME: we shouldn't use mapAsyncIterator here since it makes tests way more complex importantEmail: pubsub.getSubscriber((newEmail) => { @@ -122,7 +123,7 @@ function createSubscription(pubsub: SimplePubSub) { } async function expectPromise(promise: Promise) { - let caughtError; + let caughtError: Error; try { await promise; @@ -136,7 +137,7 @@ async function expectPromise(promise: Promise) { toReject() { expect(caughtError).to.be.an.instanceOf(Error); }, - toRejectWith(message) { + toRejectWith(message: string) { expect(caughtError).to.be.an.instanceOf(Error); expect(caughtError).to.have.property('message', message); }, @@ -312,6 +313,7 @@ describe('Subscription Initialization Phase', () => { }), }); + // TODO ts-expect-error (schema must not be null) (await expectPromise(subscribe({ schema: null, document }))).toRejectWith( 'Expected null to be a GraphQL schema.', ); @@ -321,6 +323,7 @@ describe('Subscription Initialization Phase', () => { 'Expected undefined to be a GraphQL schema.', ); + // TODO ts-expect-error (document must not be null) (await expectPromise(subscribe({ schema, document: null }))).toRejectWith( 'Must provide document.', ); diff --git a/src/subscription/mapAsyncIterator.ts b/src/subscription/mapAsyncIterator.ts index 4e9563c7526..55fc3b94993 100644 --- a/src/subscription/mapAsyncIterator.ts +++ b/src/subscription/mapAsyncIterator.ts @@ -8,7 +8,6 @@ export function mapAsyncIterator( iterable: AsyncGenerator | AsyncIterable, callback: (value: T) => PromiseOrValue, ): AsyncGenerator { - // $FlowIssue[incompatible-use] const iterator = iterable[Symbol.asyncIterator](); async function mapResult( @@ -39,9 +38,10 @@ export function mapAsyncIterator( return mapResult(await iterator.next()); }, async return(): Promise> { + // If iterator.return() does not exist, then type R must be undefined. return typeof iterator.return === 'function' ? mapResult(await iterator.return()) - : { value: undefined, done: true }; + : { value: undefined as any, done: true }; }, async throw(error?: unknown) { return typeof iterator.throw === 'function' diff --git a/src/subscription/subscribe.ts b/src/subscription/subscribe.ts index 4d194d894cc..6b4c6c13bf9 100644 --- a/src/subscription/subscribe.ts +++ b/src/subscription/subscribe.ts @@ -92,7 +92,7 @@ export async function subscribe( // the GraphQL specification. The `execute` function provides the // "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the // "ExecuteQuery" algorithm, for which `execute` is also used. - const mapSourceToResponse = (payload) => + const mapSourceToResponse = (payload: unknown) => execute({ schema, document, @@ -161,11 +161,10 @@ export async function createSourceEventStream( ); // Return early errors if execution context failed. - if (Array.isArray(exeContext)) { + if (!('schema' in exeContext)) { return { errors: exeContext }; } - // @ts-expect-error FIXME: TS Conversion const eventStream = await executeSubscription(exeContext); // Assert field returned an event stream, otherwise yield an error.