persistgraphql icon indicating copy to clipboard operation
persistgraphql copied to clipboard

Lost type information with addPersistedQueries

Open ScallyGames opened this issue 7 years ago • 5 comments

Extending on #3 when using other NetworkInterfaces this type information is lost after calling this function.

As the function expects a parameter of type NetworkInterface and returns this parameter after Object.assign the inferred type is NetworkInterface & { query: Promise<ExecutionResult> }. Thus all type information of the networkInterface extending NetworkInterface is lost.

Example

const networkInterface = addPersistedQueries(
    createNetworkInterface({
        uri: '/graphql',
    }), // creates HTTPNetworkInterface
    persistedQueries,
);
networkInterface.use(/* some middleware */);

Expectation

Above code should work, since .use() is defined on HTTPNetworkInterface.

Actual result

Throws with Property 'use' does not exist on type 'NetworkInterface & { query: (request: Request) => Promise<ExecutionResult>; }'.

Solution

The solution could look somewhat like this:

export function addPersistedQueries<T extends NetworkInterface>
  (networkInterface: T, queryMap: OutputMap) {
    let __interfaceType: T; // I think this is necessary for Generic to work correctly
   // [...]
}

ScallyGames avatar May 23 '17 14:05 ScallyGames

Yes, totally agree with this. I think the generics solution should work perfectly. Would you like to submit a PR that implements this?

Poincare avatar May 24 '17 19:05 Poincare

Can do, but probably only by next week

ScallyGames avatar May 24 '17 20:05 ScallyGames

Sure, that sounds great. Please let me know if I can help in some way.

Poincare avatar May 25 '17 22:05 Poincare

Okay, is the intended use of addPersistedQueries to call it and use the returned value or does it only enhance the existing network interface?

Replace:

   let networkInterface = new GenericNetworkInterface();
   networkInterface = addPersistedQueries(new GenericNetworkInterface(), queryMap);

Enhance:

   let networkInterface = new GenericNetworkInterface();
   addPersistedQueries(networkInterface, queryMap);

ScallyGames avatar May 29 '17 09:05 ScallyGames

As I see it now with return Object.assign(networkInterface, { /* */ } the existing object is enhanced, so it might be the better option to just not return the modified object but keep it as () => void to clarify its correct usage. With that also no type information of the original network interface is lost (what is lost however is the query(request: Request) => Promise<ExecutionResult> which matches the definition in NetworkInterface so it should not be problematic).

ScallyGames avatar May 29 '17 09:05 ScallyGames