diff --git a/types/react-relay/classic.d.ts b/types/react-relay/classic.d.ts index c600992669..e0042c3c9b 100644 --- a/types/react-relay/classic.d.ts +++ b/types/react-relay/classic.d.ts @@ -117,7 +117,7 @@ export class DefaultNetworkLayer implements RelayNetworkLayer { } export function createContainer( - component: React.ComponentClass | React.StatelessComponent, + component: React.ComponentType, params?: CreateContainerOpts ): RelayContainerClass; export function injectNetworkLayer(networkLayer: RelayNetworkLayer): any; diff --git a/types/react-relay/compat.d.ts b/types/react-relay/compat.d.ts index 22585d03d0..b74efc4ac2 100644 --- a/types/react-relay/compat.d.ts +++ b/types/react-relay/compat.d.ts @@ -1,21 +1,16 @@ -export { - QueryRenderer, - fetchQuery, - graphql, -} from "./index"; +export { QueryRenderer, fetchQuery, graphql } from "./index"; import { ConnectionConfig, RelayPaginationProp as RelayModernPaginationProp, - RelayRefetchProp as RelayModernRefetchProp + RelayRefetchProp as RelayModernRefetchProp, } from "./index"; +export { ConcreteFragment, ConcreteRequest, ConcreteBatchRequest } from "relay-runtime"; import * as RelayRuntimeTypes from "relay-runtime"; import { RelayEnvironmentInterface } from "./classic"; // ~~~~~~~~~~~~~~~~~~~~~ // Maybe Fix // ~~~~~~~~~~~~~~~~~~~~~ -export type ConcreteFragment = any; -export type ConcreteBatch = any; export type ConcreteFragmentDefinition = object; export type ConcreteOperationDefinition = object; @@ -30,7 +25,6 @@ export interface StatelessWithFragment extends React.StatelessComponent { getFragment: typeof getFragment; } export type ReactFragmentComponent = ComponentWithFragment | StatelessWithFragment; -export type ReactBaseComponent = React.ComponentClass | React.StatelessComponent; export type RelayClassicEnvironment = RelayEnvironmentInterface; // ~~~~~~~~~~~~~~~~~~~~~ @@ -68,18 +62,18 @@ export interface GeneratedNodeMap { } export function createFragmentContainer( - Component: ReactBaseComponent, + Component: React.ComponentType, fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap ): ReactFragmentComponent; export function createRefetchContainer( - Component: ReactBaseComponent, + Component: React.ComponentType, fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, taggedNode: RelayRuntimeTypes.GraphQLTaggedNode ): ReactFragmentComponent; export function createPaginationContainer( - Component: ReactBaseComponent, + Component: React.ComponentType, fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, connectionConfig: ConnectionConfig ): ReactFragmentComponent; diff --git a/types/react-relay/index.d.ts b/types/react-relay/index.d.ts index 0b7d87ce58..55848cb47c 100644 --- a/types/react-relay/index.d.ts +++ b/types/react-relay/index.d.ts @@ -11,20 +11,36 @@ export { commitLocalUpdate, commitRelayModernMutation as commitMutation, fetchRelayModernQuery as fetchQuery, + GraphQLTaggedNode, requestRelaySubscription as requestSubscription, } from "relay-runtime"; import * as React from "react"; import * as RelayRuntimeTypes from "relay-runtime"; +// ~~~~~~~~~~~~~~~~~~~~~ +// Utility types +// ~~~~~~~~~~~~~~~~~~~~~ + +// Taken from https://github.com/pelotom/type-zoo +// tslint:disable-next-line:strict-export-declare-modifiers +type Diff = ({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T]; +// tslint:disable-next-line:strict-export-declare-modifiers +type Omit = Pick>; + +export type RemoveRelayProp

= Omit

; + +export interface ComponentRef { + componentRef?: (ref: any) => void; +} + +export type RelayContainer = React.ComponentType & ComponentRef>; + // ~~~~~~~~~~~~~~~~~~~~~ // Maybe Fix // ~~~~~~~~~~~~~~~~~~~~~ -export type ConcreteFragment = any; -export type ConcreteBatch = any; export type ConcreteFragmentDefinition = object; export type ConcreteOperationDefinition = object; -export type ReactBaseComponent = React.ComponentClass | React.StatelessComponent; // ~~~~~~~~~~~~~~~~~~~~~ // RelayProp @@ -40,24 +56,19 @@ export interface RelayProp { export function RelayQL(strings: string[], ...substitutions: any[]): RelayRuntimeTypes.RelayConcreteNode; // ~~~~~~~~~~~~~~~~~~~~~ -// RelayModernGraphQLTag +// ReactRelayTypes // ~~~~~~~~~~~~~~~~~~~~~ export interface GeneratedNodeMap { - [key: string]: GraphQLTaggedNode; + [key: string]: RelayRuntimeTypes.GraphQLTaggedNode; } -export type GraphQLTaggedNode = - | (() => ConcreteFragment | ConcreteBatch) - | { - modern(): ConcreteFragment | ConcreteBatch; - classic(relayQL: typeof RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition; - }; + /** * Runtime function to correspond to the `graphql` tagged template function. * All calls to this function should be transformed by the plugin. */ export interface GraphqlInterface { - (strings: string[] | TemplateStringsArray): GraphQLTaggedNode; - experimental(strings: string[] | TemplateStringsArray): GraphQLTaggedNode; + (strings: string[] | TemplateStringsArray): RelayRuntimeTypes.GraphQLTaggedNode; + experimental(strings: string[] | TemplateStringsArray): RelayRuntimeTypes.GraphQLTaggedNode; } export const graphql: GraphqlInterface; @@ -67,7 +78,7 @@ export const graphql: GraphqlInterface; export interface QueryRendererProps { cacheConfig?: RelayRuntimeTypes.CacheConfig; environment: RelayRuntimeTypes.Environment; - query: GraphQLTaggedNode; + query: RelayRuntimeTypes.GraphQLTaggedNode; render(readyState: ReadyState): React.ReactElement | undefined | null; variables: RelayRuntimeTypes.Variables; rerunParamExperimental?: RelayRuntimeTypes.RerunParam; @@ -87,9 +98,9 @@ export class QueryRenderer extends ReactRelayQueryRenderer {} // createFragmentContainer // ~~~~~~~~~~~~~~~~~~~~~ export function createFragmentContainer( - Component: ReactBaseComponent, - fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap -): ReactBaseComponent; + Component: React.ComponentType, + fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap +): RelayContainer; // ~~~~~~~~~~~~~~~~~~~~~ // createPaginationContainer @@ -131,16 +142,16 @@ export interface ConnectionConfig { paginationInfo: { count: number; cursor?: string }, fragmentVariables: RelayRuntimeTypes.Variables ): RelayRuntimeTypes.Variables; - query: GraphQLTaggedNode; + query: RelayRuntimeTypes.GraphQLTaggedNode; } export function createPaginationContainer( - Component: ReactBaseComponent, - fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, + Component: React.ComponentType, + fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, connectionConfig: ConnectionConfig -): ReactBaseComponent; +): RelayContainer; // ~~~~~~~~~~~~~~~~~~~~~ -// createFragmentContainer +// createRefetchContainer // ~~~~~~~~~~~~~~~~~~~~~ export interface RefetchOptions { force?: boolean; @@ -157,7 +168,7 @@ export type RelayRefetchProp = RelayProp & { ): RelayRuntimeTypes.Disposable; }; export function createRefetchContainer( - Component: ReactBaseComponent, - fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, - taggedNode: GraphQLTaggedNode -): ReactBaseComponent; + Component: React.ComponentType, + fragmentSpec: RelayRuntimeTypes.GraphQLTaggedNode | GeneratedNodeMap, + taggedNode: RelayRuntimeTypes.GraphQLTaggedNode +): RelayContainer; diff --git a/types/react-relay/test/react-relay-classic-tests.tsx b/types/react-relay/test/react-relay-classic-tests.tsx index d8eaf005ca..a57cbc1b6f 100644 --- a/types/react-relay/test/react-relay-classic-tests.tsx +++ b/types/react-relay/test/react-relay-classic-tests.tsx @@ -1,15 +1,14 @@ import * as React from "react"; import * as Relay from "react-relay/classic"; +import { CompatContainer } from "./react-relay-compat-tests"; + interface Props { text: string; userId: string; } -// tslint:disable-next-line no-empty-interface -interface Response {} - -export default class AddTweetMutation extends Relay.Mutation { +export default class AddTweetMutation extends Relay.Mutation { getMutation() { return Relay.QL`mutation{addTweet}`; } @@ -64,6 +63,7 @@ const ArtworkContainer = Relay.createContainer(Artwork, { artwork: () => Relay.QL` fragment on Artwork { title + ${CompatContainer.getFragment("whatever")} } `, }, @@ -83,7 +83,7 @@ class StubbedArtwork extends React.Component { setVariables: () => {}, forceFetch: () => {}, hasOptimisticUpdate: () => false, - getPendingTransactions: (): Relay.RelayMutationTransaction[] => [], + getPendingTransactions: (): any => undefined, commitUpdate: () => {}, }, }; diff --git a/types/react-relay/test/react-relay-compat-tests.tsx b/types/react-relay/test/react-relay-compat-tests.tsx new file mode 100644 index 0000000000..e0ee5d3be2 --- /dev/null +++ b/types/react-relay/test/react-relay-compat-tests.tsx @@ -0,0 +1,53 @@ +import * as React from "react"; +import { + QueryRenderer as CompatQueryRenderer, + createFragmentContainer as createFragmentContainerCompat, + commitMutation as commitMutationCompat, + CompatEnvironment, + RelayPaginationProp as RelayPaginationPropCompat, +} from "react-relay/compat"; + +import { configs, mutation, optimisticResponse } from "./react-relay-tests"; + +// testting compat mutation with classic environment +function markNotificationAsReadCompat(environment: CompatEnvironment, source: string, storyID: string) { + const variables = { + input: { + source, + storyID, + }, + }; + + commitMutationCompat(environment, { + configs, + mutation, + optimisticResponse, + variables, + onCompleted: (response, errors) => { + console.log("Response received from server."); + }, + onError: err => console.error(err), + updater: (store, data) => { + const field = store.get(storyID); + if (field) { + field.setValue(data.story, "story"); + } + } + }); +} + +interface CompatProps { + relay: RelayPaginationPropCompat; +} + +class CompatComponent extends React.Component { + markNotificationAsRead(source: string, storyID: string) { + markNotificationAsReadCompat(this.props.relay.environment, source, storyID); + } + + render() { + return (

); + } +} + +export const CompatContainer = createFragmentContainerCompat(CompatComponent, {}); diff --git a/types/react-relay/test/react-relay-tests.tsx b/types/react-relay/test/react-relay-tests.tsx index 6fbd2dea3f..cc25f5f368 100644 --- a/types/react-relay/test/react-relay-tests.tsx +++ b/types/react-relay/test/react-relay-tests.tsx @@ -1,9 +1,6 @@ import * as React from "react"; -import { Environment, Network, RecordSource, Store, ConnectionHandler } from "relay-runtime"; +import { Environment, Network, RecordSource, Store, ConnectionHandler, FragmentReference } from "relay-runtime"; -//////////////////////////// -// RELAY MODERN TESTS -/////////////////////////// import { graphql, commitMutation, @@ -13,7 +10,8 @@ import { requestSubscription, QueryRenderer, RelayRefetchProp, - RelayPaginationProp + RelayPaginationProp, + RelayProp } from "react-relay"; // ~~~~~~~~~~~~~~~~~~~~~ @@ -54,63 +52,137 @@ const MyQueryRenderer = (props: { name: string }) => ( /> ); -// ~~~~~~~~~~~~~~~~~~~~~ -// Modern FragmentContainer -// ~~~~~~~~~~~~~~~~~~~~~ -const MyFragmentContainer = createFragmentContainer( - class TodoListView extends React.Component { - render() { - return
; - } - }, - { - item: graphql` - fragment TodoItem_item on Todo { - text - isComplete - } - `, - } -); - // ~~~~~~~~~~~~~~~~~~~~~ // Modern RefetchContainer // ~~~~~~~~~~~~~~~~~~~~~ -interface StoryInterface { - id: string; -} -interface FeedStoriesProps { - relay: RelayRefetchProp; - feed: { - stories: { edges: Array<{ node: StoryInterface }> }; - }; -} -class Story extends React.Component<{ story: StoryInterface }> {} -class FeedStories extends React.Component { - render() { - return ( -
- {this.props.feed.stories.edges.map(edge => )} -
- ); + +type StoryLike = (storyID: string) => void; + +// Artifact produced by relay-compiler-language-typescript +// tslint:disable-next-line:no-const-enum +const enum _Story_story$ref {} +type Story_story$ref = _Story_story$ref & FragmentReference; +// tslint:disable-next-line:interface-over-type-literal +type Story_story = { + readonly id: string; + readonly text: string; + readonly isPublished: boolean; + readonly " $refType": Story_story$ref; +}; + +const Story = (() => { + interface Props { + relay: RelayRefetchProp; + story: Story_story; + onLike: StoryLike; + ignoreMe?: {}; } - _loadMore() { - // Increments the number of stories being rendered by 10. - const refetchVariables = (fragmentVariables: { count: number }) => ({ - count: fragmentVariables.count + 10, + interface State { + isLoading: boolean; + } + + class Story extends React.Component { + state = { + isLoading: false + }; + + componentDidMount() { + setInterval(this.handleRefresh.bind(this), 1000); + } + + handleRefresh() { + this.setState({ isLoading: true }); + this.props.relay.refetch({ id: this.props.story.id }, {}, error => { + this.setState({ isLoading: false }); + }, { force: true }); + } + + render() { + return ( +
+ {this.props.story.isPublished ? "" : "Draft: "} + {this.props.story.text} + {this.state.isLoading && ♺} + +
+ ); + } + } + + const StoryRefetchContainer = createRefetchContainer( + Story, + { + story: graphql` + fragment Story_story on Todo { + id + text + isPublished + } + `, + }, + graphql.experimental` + query StoryRefetchQuery($id: ID!) { + story(id: $id) { + ...Story_story + } + } + ` + ); + + function doesNotRequireRelayPropToBeProvided() { + const onLike = (id: string) => console.log(`Liked story #${id}`); + const story: { " $fragmentRefs": Story_story$ref } = {} as any; + // TODO: Fix requirement to cast fragment reference as `any`. + ; + } + + return StoryRefetchContainer; +})(); + +// ~~~~~~~~~~~~~~~~~~~~~ +// Modern FragmentContainer +// ~~~~~~~~~~~~~~~~~~~~~ + +// Artifact produced by relay-compiler-language-typescript +// tslint:disable-next-line:no-const-enum +const enum _FeedStories_feed$ref {} +type FeedStories_feed$ref = _FeedStories_feed$ref & FragmentReference; +// tslint:disable-next-line:interface-over-type-literal +type FeedStories_feed = { + readonly edges: ReadonlyArray<{ + readonly node: { + readonly id: string; + readonly " $fragmentRefs": Story_story$ref; + }; + }>; + readonly " $refType": FeedStories_feed$ref; +}; + +const Feed = (() => { + interface Props { + relay: RelayProp; + feed: FeedStories_feed; + onStoryLike: StoryLike; + ignoreMe?: {}; + } + + const FeedStories: React.SFC = ({ feed, onStoryLike, relay }) => { + // TODO: Getting env here for no good reason other than needing to test it works. + // If you have a good relavant example, please update! + relay.environment; + const stories = feed.edges.map(edge => { + // TODO: Fix requirement to cast fragment reference as `any`. + return ; }); - this.props.relay.refetch(refetchVariables); - } -} + return
{stories}
; + }; -const FeedRefetchContainer = createRefetchContainer( - FeedStories, - { - feed: graphql.experimental` - fragment FeedStories_feed on Feed @argumentDefinitions(count: { type: "Int", defaultValue: 10 }) { - stories(first: $count) { + const FeedFragmentContainer = createFragmentContainer( + FeedStories, + { + feed: graphql` + fragment FeedStories_feed on Feed { edges { node { id @@ -118,104 +190,137 @@ const FeedRefetchContainer = createRefetchContainer( } } } - } - `, - }, - graphql.experimental` - query FeedStoriesRefetchQuery($count: Int) { - feed { - ...FeedStories_feed @arguments(count: $count) - } + `, } - ` -); + ); + + function doesNotRequireRelayPropToBeProvided() { + const onStoryLike = (id: string) => console.log(`Liked story #${id}`); + const feed: { " $fragmentRefs": FeedStories_feed$ref } = {} as any; + // TODO: Fix requirement to cast fragment reference as `any`. + ; + } + + return FeedFragmentContainer; +})(); // ~~~~~~~~~~~~~~~~~~~~~ // Modern PaginationContainer // ~~~~~~~~~~~~~~~~~~~~~ -interface FeedProps { - user: { feed: { edges: Array<{ node: StoryInterface }> } }; - relay: RelayPaginationProp; -} -class Feed extends React.Component { - render() { - return ( -
- {this.props.user.feed.edges.map(edge => )} -
- ); + +// Artifact produced by relay-compiler-language-typescript +// tslint:disable-next-line:no-const-enum +const enum _UserFeed_user$ref {} +type UserFeed_user$ref = _UserFeed_user$ref & FragmentReference; +// tslint:disable-next-line:interface-over-type-literal +type UserFeed_user = { + readonly feed: { + readonly pageInfo: { + readonly endCursor?: string | null; + readonly hasNextPage: boolean; + }; + readonly " $fragmentRefs": FeedStories_feed$ref; + }; + readonly " $refType": UserFeed_user$ref; +}; + +() => { + interface Props { + relay: RelayPaginationProp; + loadMoreTitle: string; + user: UserFeed_user; + ignoreMe?: {}; } - _loadMore() { - if (!this.props.relay.hasMore() || this.props.relay.isLoading()) { - return; + class UserFeed extends React.Component { + render() { + const onStoryLike = (id: string) => console.log(`Liked story #${id}`); + // TODO: Fix requirement to cast fragment reference as `any`. + const feed = this.props.user.feed as any; + return ( +
+ +
+ ); } - this.props.relay.loadMore( - 10, // Fetch the next 10 feed items - e => { - console.log(e); + _loadMore() { + if (!this.props.relay.hasMore() || this.props.relay.isLoading()) { + return; } - ); - } -} -const FeedPaginationContainer = createPaginationContainer( - Feed, - { - user: graphql` - fragment Feed_user on User { - feed( - first: $count - after: $cursor - orderby: $orderBy # other variables - ) @connection(key: "Feed_feed") { - edges { - node { - id - ...Story_story + this.props.relay.loadMore( + 10, // Fetch the next 10 feed items + e => { + console.log(e); + } + ); + } + } + + const UserFeedPaginationContainer = createPaginationContainer( + UserFeed, + { + user: graphql` + fragment UserFeed_user on User { + feed( + first: $count + after: $cursor + orderby: $orderBy # other variables + ) @connection(key: "Feed_feed") { + ...FeedStories_feed + pageInfo { + endCursor + hasNextPage } } } - } - `, - }, - { - direction: "forward", - getConnectionFromProps(props) { - return props.user && props.user.feed; + `, }, - getFragmentVariables(prevVars, totalCount) { - return { - ...prevVars, - count: totalCount, - }; - }, - getVariables(props, { count, cursor }, fragmentVariables) { - return { - count, - cursor, - // in most cases, for variables other than connection filters like - // `first`, `after`, etc. you may want to use the previous values. - orderBy: fragmentVariables.orderBy, - }; - }, - query: graphql` - query FeedPaginationQuery($count: Int!, $cursor: String, $orderby: String!) { - user { - # You could reference the fragment defined previously. - ...Feed_user + { + direction: "forward", + getConnectionFromProps(props) { + // TODO: Fix requirement to have `edges` and both `pageInfo` details for forward and backward pagination + return props.user && props.user.feed as any; + }, + getFragmentVariables(prevVars, totalCount) { + return { + ...prevVars, + count: totalCount, + }; + }, + getVariables(props, { count, cursor }, fragmentVariables) { + return { + count, + cursor, + // in most cases, for variables other than connection filters like + // `first`, `after`, etc. you may want to use the previous values. + orderBy: fragmentVariables.orderBy, + }; + }, + query: graphql` + query FeedPaginationQuery($count: Int!, $cursor: String, $orderby: String!) { + user { + # You could reference the fragment defined previously. + ...Feed_user + } } - } - `, + `, + } + ); + + function doesNotRequireRelayPropToBeProvided() { + const user: { " $fragmentRefs": UserFeed_user$ref } = {} as any; + // TODO: Fix requirement to cast fragment reference as `any`. + ; } -); +}; // ~~~~~~~~~~~~~~~~~~~~~ // Modern Mutations // ~~~~~~~~~~~~~~~~~~~~~ -const mutation = graphql` +export const mutation = graphql` mutation MarkReadNotificationMutation($input: MarkReadNotificationData!) { markReadNotification(data: $input) { notification { @@ -225,7 +330,7 @@ const mutation = graphql` } `; -const optimisticResponse = { +export const optimisticResponse = { markReadNotification: { notification: { seenState: "SEEN", @@ -233,7 +338,7 @@ const optimisticResponse = { }, }; -const configs = [ +export const configs = [ { type: "NODE_DELETE" as "NODE_DELETE", deletedIDFieldName: "destroyedShipId", @@ -325,150 +430,3 @@ requestSubscription( }, } ); - -//////////////////////////// -// RELAY COMPAT TESTS -/////////////////////////// -import { - QueryRenderer as CompatQueryRenderer, - createFragmentContainer as createFragmentContainerCompat, - commitMutation as commitMutationCompat, - CompatEnvironment, - RelayPaginationProp as RelayPaginationPropCompat, -} from "react-relay/compat"; - -// testting compat mutation with classic environment -function markNotificationAsReadCompat(environment: CompatEnvironment, source: string, storyID: string) { - const variables = { - input: { - source, - storyID, - }, - }; - - commitMutationCompat(environment, { - configs, - mutation, - optimisticResponse, - variables, - onCompleted: (response, errors) => { - console.log("Response received from server."); - }, - onError: err => console.error(err), - updater: (store, data) => { - const field = store.get(storyID); - if (field) { - field.setValue(data.story, "story"); - } - } - }); -} - -interface CompatProps { - relay: RelayPaginationPropCompat; -} - -export class CompatComponent extends React.Component { - markNotificationAsRead(source: string, storyID: string) { - markNotificationAsReadCompat(this.props.relay.environment, source, storyID); - } - - render() { - return (
); - } -} - -const CompatContainer = createFragmentContainerCompat(CompatComponent, {}); - -//////////////////////////// -// RELAY-CLASSIC TESTS -/////////////////////////// -import * as Relay from "react-relay/classic"; - -interface Props { - text: string; - userId: string; -} - -export default class AddTweetMutation extends Relay.Mutation { - getMutation() { - return Relay.QL`mutation{addTweet}`; - } - - getFatQuery() { - return Relay.QL` - fragment on AddTweetPayload { - tweetEdge - user - } - `; - } - - getConfigs() { - return [ - { - type: "RANGE_ADD", - parentName: "user", - parentID: this.props.userId, - connectionName: "tweets", - edgeName: "tweetEdge", - rangeBehaviors: { - "": "append", - }, - }, - ]; - } - - getVariables() { - return this.props; - } -} - -interface ArtwokRelayVariables { - artworkID: string; -} - -interface ArtworkProps extends Relay.RelayProps { - artwork: { - title: string; - }; -} - -class Artwork extends React.Component { - render() { - return {this.props.artwork.title}; - } -} - -const ArtworkContainer = Relay.createContainer(Artwork, { - fragments: { - artwork: () => Relay.QL` - fragment on Artwork { - title - ${ CompatContainer.getFragment('whatever') } - } - `, - }, -}); - -class StubbedArtwork extends React.Component { - render() { - const props = { - artwork: { title: "CHAMPAGNE FORMICA FLAG" }, - relay: { - route: { - name: "champagne", - }, - variables: { - artworkID: "champagne-formica-flag", - }, - setVariables: () => {}, - forceFetch: () => {}, - hasOptimisticUpdate: () => false, - getPendingTransactions: (): any => undefined, - commitUpdate: () => {}, - }, - }; - return ; - } -} diff --git a/types/react-relay/tsconfig.json b/types/react-relay/tsconfig.json index 937fa22803..bf3dc05339 100644 --- a/types/react-relay/tsconfig.json +++ b/types/react-relay/tsconfig.json @@ -24,6 +24,7 @@ "classic.d.ts", "compat.d.ts", "test/react-relay-tests.tsx", + "test/react-relay-compat-tests.tsx", "test/react-relay-classic-tests.tsx" ] } \ No newline at end of file diff --git a/types/relay-runtime/index.d.ts b/types/relay-runtime/index.d.ts index 74b24ca1b8..2348a4d06b 100644 --- a/types/relay-runtime/index.d.ts +++ b/types/relay-runtime/index.d.ts @@ -17,8 +17,6 @@ export type RelayConcreteNode = any; export type RelayMutationTransaction = any; export type RelayMutationRequest = any; export type RelayQueryRequest = any; -export type ConcreteFragment = any; -export type ConcreteBatch = any; export type ConcreteFragmentDefinition = object; export type ConcreteOperationDefinition = object; @@ -32,6 +30,23 @@ export type ConcreteOperationDefinition = object; */ export type RelayContainer = any; +// ~~~~~~~~~~~~~~~~~~~~~ +// Used in artifacts +// emitted by +// relay-compiler +// ~~~~~~~~~~~~~~~~~~~~~ + +// File: https://github.com/facebook/relay/blob/fe0e70f10bbcba1fff89911313ea69f24569464b/packages/relay-runtime/util/RelayConcreteNode.js +export type ConcreteFragment = any; +export type ConcreteRequest = any; +export type ConcreteBatchRequest = any; + +export type RequestNode = ConcreteRequest | ConcreteBatchRequest; + +// Using `enum` here to create a distinct type and `const` to ensure it doesn’t leave any generated code. +// tslint:disable-next-line:no-const-enum +export const enum FragmentReference {} + // ~~~~~~~~~~~~~~~~~~~~~ // RelayQL // ~~~~~~~~~~~~~~~~~~~~~ @@ -44,9 +59,9 @@ export interface GeneratedNodeMap { [key: string]: GraphQLTaggedNode; } export type GraphQLTaggedNode = - | (() => ConcreteFragment | ConcreteBatch) + | (() => ConcreteFragment | RequestNode) | { - modern(): ConcreteFragment | ConcreteBatch; + modern(): ConcreteFragment | RequestNode; classic(relayQL: RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition; }; // ~~~~~~~~~~~~~~~~~~~~~ @@ -85,7 +100,7 @@ export interface PayloadError { * May return an Observable or Promise of a raw server response. */ export function FetchFunction( - operation: ConcreteBatch, + operation: RequestNode, variables: Variables, cacheConfig: CacheConfig, uploadables?: UploadableMap @@ -99,7 +114,7 @@ export function FetchFunction( * fourth parameter. */ export type SubscribeFunction = ( - operation: ConcreteBatch, + operation: RequestNode, variables: Variables, cacheConfig: CacheConfig, observer: LegacyObserver diff --git a/types/relay-runtime/relay-runtime-tests.tsx b/types/relay-runtime/relay-runtime-tests.tsx index b39a117e61..4cbbacf680 100644 --- a/types/relay-runtime/relay-runtime-tests.tsx +++ b/types/relay-runtime/relay-runtime-tests.tsx @@ -1,4 +1,12 @@ -import { Environment, Network, RecordSource, Store, ConnectionHandler, ViewerHandler, RecordSourceInspector } from "relay-runtime"; +import { + Environment, + Network, + RecordSource, + Store, + ConnectionHandler, + ViewerHandler, + RecordSourceInspector, +} from "relay-runtime"; const source = new RecordSource(); const store = new Store(source);