apollographql / graphql-subscriptions

:newspaper: A small module that implements GraphQL subscriptions for Node.js
MIT License
1.59k stars 133 forks source link

Generic types for pubSub (with solution) #223

Open Akxe opened 4 years ago

Akxe commented 4 years ago

By adding generic to PubSubEngine, a lot of typos and (hard) type lookup can be prevented.

Here is an example of the type definition to look like in the end.

const pubSub = new PubSub<{
    commentsChanged: Comment[],
    postsChanged: Post[],
}>();

//  `pubSub.publish` will now only accept keys listed in generic type of `pubSub` instance 
// **The type must match too!**
pubSub.publish('commentAdded', { commentAdded: new Comment( /*...*/ )] });

Here is what needed to be done. (I looked that there is an ongoing change to rename asyncIterator and didn't felt like dealing with it.)

pubsub-engine.d.ts

export type PubSubEngineGeneric = {
    [key: string]: any;
}

export declare abstract class PubSubEngine<T extends PubSubEngineGeneric> {
    abstract publish<key extends keyof T>(triggerName: key, payload: { [key]: T[key] }): Promise<void>;
    abstract subscribe<key extends keyof T>(triggerName: key, onMessage: Function, options: Object): Promise<number>;
    abstract unsubscribe(subId: number): any;
    asyncIterator<key extends keyof T>(triggers: key | key[]): AsyncIterator<T[key]>;
}

pubsub.d.ts

/// <reference types="node" />
import { EventEmitter } from 'events';
import { PubSubEngine, PubSubEngineGeneric } from './pubsub-engine';
export interface PubSubOptions {
    eventEmitter?: EventEmitter;
}
export declare class PubSub<T extends PubSubEngineGeneric = any> extends PubSubEngine<T> {
    protected ee: EventEmitter;
    private subscriptions;
    private subIdCounter;
    constructor(options?: PubSubOptions);
    get<key extends keyof T>(prop: key): T[key];
    publish<key extends keyof T>(triggerName: key, payload: { [key]: T[key] }): Promise<void>;
    subscribe(triggerName: string, onMessage: (...args: any[]) => void): Promise<number>;
    unsubscribe(subId: number): void;
}