Skip to content

Commit

Permalink
TS: Fix strict issues in src/subscription
Browse files Browse the repository at this point in the history
  • Loading branch information
leebyron committed May 27, 2021
1 parent 6858154 commit f41145b
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 20 deletions.
18 changes: 11 additions & 7 deletions src/subscription/__tests__/mapAsyncIterator-test.ts
Expand Up @@ -33,7 +33,9 @@ describe('mapAsyncIterator', () => {

next(): Promise<IteratorResult<number, void>> {
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 });
Expand Down Expand Up @@ -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,
});
Expand All @@ -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,
});
},
};
Expand All @@ -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,
});
Expand Down Expand Up @@ -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,
});
},
};
Expand Down
14 changes: 10 additions & 4 deletions 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.
Expand All @@ -18,7 +20,7 @@ export class SimplePubSub<T> {

getSubscriber<R>(transform: (value: T) => R): AsyncGenerator<R, void, void> {
const pullQueue: Array<(result: IteratorResult<R, void>) => void> = [];
const pushQueue = [];
const pushQueue: Array<R> = [];
let listening = true;
this._subscribers.add(pushValue);

Expand All @@ -33,13 +35,15 @@ export class SimplePubSub<T> {
};

return {
next() {
next(): Promise<IteratorResult<R, void>> {
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));
},
Expand All @@ -59,7 +63,9 @@ export class SimplePubSub<T> {
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);
}
Expand Down
11 changes: 7 additions & 4 deletions src/subscription/__tests__/subscribe-test.ts
Expand Up @@ -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) },
},
Expand Down Expand Up @@ -103,7 +104,7 @@ function createSubscription(pubsub: SimplePubSub<Email>) {
},
];

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) => {
Expand All @@ -122,7 +123,7 @@ function createSubscription(pubsub: SimplePubSub<Email>) {
}

async function expectPromise(promise: Promise<unknown>) {
let caughtError;
let caughtError: Error;

try {
await promise;
Expand All @@ -136,7 +137,7 @@ async function expectPromise(promise: Promise<unknown>) {
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);
},
Expand Down Expand Up @@ -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.',
);
Expand All @@ -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.',
);
Expand Down
4 changes: 2 additions & 2 deletions src/subscription/mapAsyncIterator.ts
Expand Up @@ -8,7 +8,6 @@ export function mapAsyncIterator<T, U, R = undefined>(
iterable: AsyncGenerator<T, R, void> | AsyncIterable<T>,
callback: (value: T) => PromiseOrValue<U>,
): AsyncGenerator<U, R, void> {
// $FlowIssue[incompatible-use]
const iterator = iterable[Symbol.asyncIterator]();

async function mapResult(
Expand Down Expand Up @@ -39,9 +38,10 @@ export function mapAsyncIterator<T, U, R = undefined>(
return mapResult(await iterator.next());
},
async return(): Promise<IteratorResult<U, R>> {
// 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'
Expand Down
5 changes: 2 additions & 3 deletions src/subscription/subscribe.ts
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit f41145b

Please sign in to comment.