facebook / relay

Relay is a JavaScript framework for building data-driven React applications.
https://relay.dev
MIT License
18.41k stars 1.83k forks source link

Cannot setup network layer to handle subscriptions using example from docs. Relay 12 #3713

Open frybin opened 2 years ago

frybin commented 2 years ago

When following the example on how to set up the network layer to handle subscriptions from the docs site I am receiving multiple errors trying to set up the network layer in a create-react-app app initialized in typescript.

The first Error I get is.

TS2345: Argument of type 'Observable<ExecutionResult<{ [key: string]: any; }, { [key: string]: any; }>>' is not assignable to parameter of type 'ObservableFromValue<ExecutionResult<{ [key: string]: any; }, { [key: string]: any; }>>'.
  Type 'Observable<ExecutionResult<{ [key: string]: any; }, { [key: string]: any; }>>' is not assignable to type 'Subscribable<ExecutionResult<{ [key: string]: any; }, { [key: string]: any; }>>'.
    The types returned by 'subscribe(...)' are incompatible between these types.
      Property 'closed' is missing in type '{ unsubscribe: () => void; }' but required in type 'Subscription'.
    42 |   });
    43 |
  > 44 |   return Observable.from(subscribeObservable);
       |                          ^^^^^^^^^^^^^^^^^^^
    45 | };

I was able to solve this issue by changing

const subscribe = (request: { text: any; name: any }, variables: any) => {
  const subscribeObservable = subscriptionClient.request({
    query: request.text,
    operationName: request.name,
    variables,
  });

  return Observable.from(subscribeObservable);
};

to

 const subscribe = (request: { text: any; name: any }, variables: any) => {
  const subscribeObservable = subscriptionClient
    .request({
      query: request.text,
      operationName: request.name,
      variables,
    })
    .subscribe({
      next: (data: any) => {
        console.log(data);
      },
      error: (error: any) => {
        console.log(error);
      },
      complete: () => {
        console.log("complete");
      },
    });

  return Observable.from(subscribeObservable);
};

And now the issue I am getting is:

 TS2345: Argument of type '(request: {    text: any;    name: any;}, variables: any) => Observable<{ unsubscribe: () => void; }>' is not assignable to parameter of type 'SubscribeFunction'.
  Type 'RelayObservable<{ unsubscribe: () => void; }>' is not assignable to type 'RelayObservable<GraphQLResponse> | Disposable'.
    Type 'RelayObservable<{ unsubscribe: () => void; }>' is not assignable to type 'RelayObservable<GraphQLResponse>'.
      Type '{ unsubscribe: () => void; }' is not assignable to type 'GraphQLResponse'.
        Type '{ unsubscribe: () => void; }' is missing the following properties from type 'readonly GraphQLSingularResponse[]': length, concat, join, slice, and 18 more.
    58 |
    59 | const environment = new Environment({
  > 60 |   network: Network.create(fetchQuery, subscribe),
       |                                       ^^^^^^^^^
    61 |   store: new Store(new RecordSource()),
    62 | });

Below are the contents of the file where I am trying to set up the network layer.

import {
  Environment,
  Network,
  RecordSource,
  RequestParameters,
  Store,
  Variables,
  Observable,
} from "relay-runtime";

import { SubscriptionClient } from "subscriptions-transport-ws";

async function fetchQuery(operation: RequestParameters, variables: Variables) {
  const response = await fetch(
    process.env.REACT_APP_GRAPHQL_URL || "http://localhost:8080/api/query",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        query: operation.text,
        variables,
      }),
    }
  );
  return await response.json();
}

const websocketURL =
  process.env.REACT_APP_GRAPHQL_URL || "ws://localhost:8080/api/query";

const subscriptionClient = new SubscriptionClient(websocketURL, {
  reconnect: true,
});

const subscribe = (request: { text: any; name: any }, variables: any) => {
  const subscribeObservable = subscriptionClient
    .request({
      query: request.text,
      operationName: request.name,
      variables,
    })
    .subscribe({
      next: (data: any) => {
        console.log(data);
      },
      error: (error: any) => {
        console.log(error);
      },
      complete: () => {
        console.log("complete");
      },
    });

  return Observable.from(subscribeObservable);
};

const environment = new Environment({
  network: Network.create(fetchQuery, subscribe),
  store: new Store(new RecordSource()),
});

export default environment;
alunyov commented 2 years ago

@frybin we do not maintain the typescript for Relay. You probably need to update something here: https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/relay-runtime

tobias-tengler commented 2 years ago

Just ran into this as well. I think the team should actively maintain these types.

I know you only care about Flow at Meta, but I would say Typescript is definitely the open-source standard nowadays. At least I haven't seen a React project without Typescript in a while.

If the team wants to improve the open-source Relay experience, I think this is definitely one area to start!

EDIT: Although in this specific case, there's a 3rd party library for the subscriptions involved - so it might be that you guys can't even do anything.