From 694fb9b2286ba5d37d3c8a4d85e05dd9a6c855b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 11 Oct 2017 15:08:00 +0200 Subject: [PATCH 1/7] [Relay] Change imports to work as per normal usage. --- .../react-relay-classic.d.ts => classic.d.ts} | 0 .../react-relay-compat.d.ts => compat.d.ts} | 4 +- types/react-relay/index.d.ts | 175 +------ .../react-relay-modern.d.ts => modern.d.ts} | 0 .../react-relay/react-relay-classic-tests.tsx | 92 ++++ types/react-relay/react-relay-tests.tsx | 401 +++++++++++++++- types/react-relay/tsconfig.json | 10 +- types/react-relay/{v1 => }/tslint.json | 0 types/react-relay/v1/index.d.ts | 23 - types/react-relay/v1/react-relay-tests.tsx | 445 ------------------ types/react-relay/v1/tsconfig.json | 33 -- 11 files changed, 497 insertions(+), 686 deletions(-) rename types/react-relay/{v1/lib/react-relay-classic.d.ts => classic.d.ts} (100%) rename types/react-relay/{v1/lib/react-relay-compat.d.ts => compat.d.ts} (95%) rename types/react-relay/{v1/lib/react-relay-modern.d.ts => modern.d.ts} (100%) create mode 100644 types/react-relay/react-relay-classic-tests.tsx rename types/react-relay/{v1 => }/tslint.json (100%) delete mode 100644 types/react-relay/v1/index.d.ts delete mode 100644 types/react-relay/v1/react-relay-tests.tsx delete mode 100644 types/react-relay/v1/tsconfig.json diff --git a/types/react-relay/v1/lib/react-relay-classic.d.ts b/types/react-relay/classic.d.ts similarity index 100% rename from types/react-relay/v1/lib/react-relay-classic.d.ts rename to types/react-relay/classic.d.ts diff --git a/types/react-relay/v1/lib/react-relay-compat.d.ts b/types/react-relay/compat.d.ts similarity index 95% rename from types/react-relay/v1/lib/react-relay-compat.d.ts rename to types/react-relay/compat.d.ts index 0d6197d2eb..e16bbb01f9 100644 --- a/types/react-relay/v1/lib/react-relay-compat.d.ts +++ b/types/react-relay/compat.d.ts @@ -1,6 +1,6 @@ import { RelayRuntimeTypes, RelayCommonTypes } from 'relay-runtime'; -import { RelayEnvironmentInterface } from './react-relay-classic'; -import {} from './react-relay-modern'; +import { RelayEnvironmentInterface } from 'react-relay/classic'; +import {} from 'react-relay/modern'; // ~~~~~~~~~~~~~~~~~~~~~ // Maybe Fix diff --git a/types/react-relay/index.d.ts b/types/react-relay/index.d.ts index 4f9f49e5e7..72a661e6b7 100644 --- a/types/react-relay/index.d.ts +++ b/types/react-relay/index.d.ts @@ -1,160 +1,23 @@ -// Type definitions for react-relay 0.9.2 +// Type definitions for react-relay 1.3 // Project: https://github.com/facebook/relay -// Definitions by: Johannes Schickling +// Definitions by: Johannes Schickling , Matt Martin // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.4 -declare module "react-relay" { - import * as React from "react"; +import { RelayRuntimeTypes } from 'relay-runtime'; +import * as ReactRelayModernTypes from 'react-relay/modern'; - type ClientMutationID = string; - - /** Fragments are a hash of functions */ - interface Fragments { - [query: string]: ((variables?: RelayVariables) => string) - } - - interface CreateContainerOpts { - initialVariables?: any - fragments: Fragments - prepareVariables?(prevVariables: RelayVariables): RelayVariables - } - - interface RelayVariables { - [name: string]: any - } - - /** add static getFragment method to the component constructor */ - interface RelayContainerClass extends React.ComponentClass { - getFragment: ((q: string, v?: RelayVariables) => string) - } - - interface RelayQueryRequestResolve { - response: any - } - - type RelayMutationStatus = - 'UNCOMMITTED' | // Transaction hasn't yet been sent to the server. Transaction can be committed or rolled back. - 'COMMIT_QUEUED' | // Transaction was committed but another transaction with the same collision key is pending, so the transaction has been queued to send to the server. - 'COLLISION_COMMIT_FAILED' | //Transaction was queued for commit but another transaction with the same collision key failed. All transactions in the collision queue, including this one, have been failed. Transaction can be recommitted or rolled back. - 'COMMITTING' | // Transaction is waiting for the server to respond. - 'COMMIT_FAILED'; - - class RelayMutationTransaction { - applyOptimistic(): RelayMutationTransaction; - commit(): RelayMutationTransaction | null; - recommit(): void; - rollback(): void; - getError(): Error; - getStatus(): RelayMutationStatus; - getHash(): string; - getID(): ClientMutationID; - } - - interface RelayMutationRequest { - getQueryString(): string - getVariables(): RelayVariables - resolve(result: RelayQueryRequestResolve): any - reject(errors: any): any - } - - interface RelayQueryRequest { - resolve(result: RelayQueryRequestResolve): any - reject(errors: any): any - - getQueryString(): string - getVariables(): RelayVariables - getID(): string - getDebugName(): string - } - - interface RelayNetworkLayer { - supports(...options: string[]): boolean - } - - class DefaultNetworkLayer implements RelayNetworkLayer { - constructor(host: string, options?: any) - supports(...options: string[]): boolean - } - - function createContainer(component: React.ComponentClass | React.StatelessComponent, params?: CreateContainerOpts): RelayContainerClass - function injectNetworkLayer(networkLayer: RelayNetworkLayer): any - function isContainer(component: React.ComponentClass): boolean - function QL(...args: any[]): string - - class Route { - constructor(params?: RelayVariables) - } - - /** - * Relay Mutation class, where T are the props it takes and S is the returned payload from Relay.Store.update. - * S is typically dynamic as it depends on the data the app is currently using, but it's possible to always - * return some data in the payload using REQUIRED_CHILDREN which is where specifying S is the most useful. - */ - class Mutation { - props: T - - constructor(props: T) - static getFragment(q: string): string - } - - interface Transaction { - getError(): Error - Status(): number - } - - interface StoreUpdateCallbacks { - onFailure?(transaction: Transaction): any - onSuccess?(response: T): any - } - - interface Store { - commitUpdate(mutation: Mutation, callbacks?: StoreUpdateCallbacks): any - } - - var Store: Store - - class RootContainer extends React.Component {} - - interface RootContainerProps extends React.Props{ - Component: RelayContainerClass - route: Route - renderLoading?(): JSX.Element - renderFetched?(data: any): JSX.Element - renderFailure?(error: Error, retry: Function): JSX.Element - } - - type ReadyStateEvent = - 'ABORT' | - 'CACHE_RESTORED_REQUIRED' | - 'CACHE_RESTORE_FAILED' | - 'CACHE_RESTORE_START' | - 'NETWORK_QUERY_ERROR' | - 'NETWORK_QUERY_RECEIVED_ALL' | - 'NETWORK_QUERY_RECEIVED_REQUIRED' | - 'NETWORK_QUERY_START' | - 'STORE_FOUND_ALL' | - 'STORE_FOUND_REQUIRED'; - - interface OnReadyStateChange { - (readyState: { - ready: boolean, - done: boolean, - stale: boolean, - error?: Error, - events: Array, - aborted: boolean - }): void - } - - interface RelayProp { - readonly route: { name: string; }; // incomplete, also has params and queries - readonly variables: any; - readonly pendingVariables?: any | null; - setVariables(variables: any, onReadyStateChange?: OnReadyStateChange): void; - forceFetch(variables: any, onReadyStateChange?: OnReadyStateChange): void; - hasOptimisticUpdate(record: any): boolean; - getPendingTransactions(record: any): RelayMutationTransaction[]; - commitUpdate: (mutation: Mutation, callbacks?: StoreUpdateCallbacks) => any; - } -} +// ~~~~~~~~~~~~~~~~~~~~~ +// React-Relay Modern +// ~~~~~~~~~~~~~~~~~~~~~ +export import QueryRenderer = ReactRelayModernTypes.ReactRelayQueryRenderer; +export import createFragmentContainer = ReactRelayModernTypes.createFragmentContainer; +export import createPaginationContainer = ReactRelayModernTypes.createPaginationContainer; +export import createRefetchContainer = ReactRelayModernTypes.createRefetchContainer; +export import graphql = ReactRelayModernTypes.graphql; +export import commitLocalUpdate = RelayRuntimeTypes.commitLocalUpdate; +export import commitMutation = RelayRuntimeTypes.commitRelayModernMutation; +export import fetchQuery = RelayRuntimeTypes.fetchRelayModernQuery; +export import requestSubscription = RelayRuntimeTypes.requestRelaySubscription; +// exported for convenience +export import ModernTypes = ReactRelayModernTypes; diff --git a/types/react-relay/v1/lib/react-relay-modern.d.ts b/types/react-relay/modern.d.ts similarity index 100% rename from types/react-relay/v1/lib/react-relay-modern.d.ts rename to types/react-relay/modern.d.ts diff --git a/types/react-relay/react-relay-classic-tests.tsx b/types/react-relay/react-relay-classic-tests.tsx new file mode 100644 index 0000000000..b7531598eb --- /dev/null +++ b/types/react-relay/react-relay-classic-tests.tsx @@ -0,0 +1,92 @@ +import * as React from "react" +import * as Relay from "react-relay/classic" + +interface Props { + text: string + userId: string +} + +interface Response { +} + +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 ArtworkProps { + artwork: { + title: string + }, + relay: Relay.RelayProp, +} + +class Artwork extends React.Component { + render() { + return ( + + {this.props.artwork.title} + + ) + } +} + +const ArtworkContainer = Relay.createContainer(Artwork, { + fragments: { + artwork: () => Relay.QL` + fragment on Artwork { + title + } + ` + } +}) + +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: (): Relay.RelayMutationTransaction[] => undefined, + commitUpdate: () => {}, + } + } + return + } +} diff --git a/types/react-relay/react-relay-tests.tsx b/types/react-relay/react-relay-tests.tsx index 90425156cc..50506ac111 100644 --- a/types/react-relay/react-relay-tests.tsx +++ b/types/react-relay/react-relay-tests.tsx @@ -1,30 +1,383 @@ -import * as React from "react" -import * as Relay from "react-relay" +import * as React from "react"; +import { + Environment, + Network, + RecordSource, + Store, + ConnectionHandler, +} from 'relay-runtime'; -interface Props { - text: string - userId: string +//////////////////////////// +// RELAY MODERN TESTS +/////////////////////////// +import { + graphql, + commitMutation, + createFragmentContainer, + createPaginationContainer, + createRefetchContainer, + requestSubscription, + QueryRenderer, + ModernTypes, +} from "react-relay"; + +// ~~~~~~~~~~~~~~~~~~~~~ +// Modern Environment +// ~~~~~~~~~~~~~~~~~~~~~ +function fetchQuery(operation: any, variables: any, cacheConfig: {}) { + return fetch('/graphql'); } +const network = Network.create(fetchQuery); +const source = new RecordSource(); +const store = new Store(source); +const modernEnvironment = new Environment({ network, store }); -interface Response { +// ~~~~~~~~~~~~~~~~~~~~~ +// Modern QueryRenderer +// ~~~~~~~~~~~~~~~~~~~~~ +const MyQueryRenderer = (props: { name: string}) => ( + { + if (error) { + return
{error.message}
; + } else if (props) { + return
{props.name} is great!
; + } + return
Loading
; + }} + /> +); + +// ~~~~~~~~~~~~~~~~~~~~~ +// 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: ModernTypes.RelayRefetchProp; + feed: { + stories: { edges: Array<{ node: StoryInterface }> } + }; } - -export default class AddTweetMutation extends Relay.Mutation { - - getMutation () { - return Relay.QL`mutation{addTweet}` +class Story extends React.Component<{ story: StoryInterface }> {} +class FeedStories extends React.Component { + render() { + return ( +
+ {this.props.feed.stories.edges.map( + edge => + )} +
+ ); } - getFatQuery () { + _loadMore() { + // Increments the number of stories being rendered by 10. + const refetchVariables = (fragmentVariables: {count: number }) => ({ + count: fragmentVariables.count + 10, + }); + this.props.relay.refetch(refetchVariables); + } + } + +const FeedRefetchContainer = createRefetchContainer( + FeedStories, + { + feed: graphql.experimental` + fragment FeedStories_feed on Feed + @argumentDefinitions( + count: {type: "Int", defaultValue: 10} + ) { + stories(first: $count) { + edges { + node { + id + ...Story_story + } + } + } + } + ` + }, + graphql.experimental` + query FeedStoriesRefetchQuery($count: Int) { + feed { + ...FeedStories_feed @arguments(count: $count) + } + } + `, + ); + +// ~~~~~~~~~~~~~~~~~~~~~ +// Modern PaginationContainer +// ~~~~~~~~~~~~~~~~~~~~~ +interface FeedProps { + user: { feed: { edges: Array<{ node: StoryInterface}>}}; + relay: ModernTypes.RelayPaginationProp; +} +class Feed extends React.Component { + render() { + return (
+ {this.props.user.feed.edges.map( + edge => + )} +
); + } + + _loadMore() { + if (!this.props.relay.hasMore() || this.props.relay.isLoading()) { + return; + } + + this.props.relay.loadMore( + 10, // Fetch the next 10 feed items + e => { + console.log(e); + }, + ); + } +} + +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 + } + } + } + } + `, + }, + { + direction: 'forward', + getConnectionFromProps(props: { user: {feed: any}}) { + 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 + } + } + ` + } +); + +// ~~~~~~~~~~~~~~~~~~~~~ +// Modern Mutations +// ~~~~~~~~~~~~~~~~~~~~~ +const mutation = graphql` +mutation MarkReadNotificationMutation( + $input: MarkReadNotificationData! +) { + markReadNotification(data: $input) { + notification { + seenState + } + } +} +`; + +const optimisticResponse = { + markReadNotification: { + notification: { + seenState: 'SEEN', + }, + }, +}; + +const configs = [{ + type: 'NODE_DELETE' as 'NODE_DELETE', + deletedIDFieldName: 'destroyedShipId', +}, { + type: 'RANGE_ADD' as 'RANGE_ADD', + parentID: 'shipId', + connectionInfo: [{ + key: 'AddShip_ships', + rangeBehavior: 'append', + }], + edgeName: 'newShipEdge', +}, { + type: 'RANGE_DELETE' as 'RANGE_DELETE', + parentID: 'todoId', + connectionKeys: [{ + key: 'RemoveTags_tags', + rangeBehavior: 'append', + }], + pathToConnection: ['todo', 'tags'], + deletedIDFieldName: 'removedTagId' +}]; + +function markNotificationAsRead(source: string, storyID: string) { + const variables = { + input: { + source, + storyID, + }, + }; + + commitMutation( + modernEnvironment, + { + configs, + mutation, + optimisticResponse, + variables, + onCompleted: (response, errors) => { + console.log('Response received from server.'); + }, + onError: err => console.error(err), + }, + ); +} + +// ~~~~~~~~~~~~~~~~~~~~~ +// Modern Subscriptions +// ~~~~~~~~~~~~~~~~~~~~~ +const subscription = graphql` + subscription MarkReadNotificationSubscription( + $storyID: ID! + ) { + markReadNotification(storyID: $storyID) { + notification { + seenState + } + } + } +`; +const variables = { + storyID: '123', +}; +requestSubscription( + modernEnvironment, // see Environment docs + { + subscription, + variables, + // optional but recommended: + onCompleted: () => {}, + onError: error => console.error(error), + // example of a custom updater + updater: store => { + // Get the notification + const rootField = store.getRootField('markReadNotification'); + const notification = !!rootField && rootField.getLinkedRecord('notification'); + // Add it to a connection + const viewer = store.getRoot().getLinkedRecord('viewer'); + const notifications = + ConnectionHandler.getConnection(viewer, 'notifications'); + const edge = ConnectionHandler.createEdge( + store, + notifications, + notification, + '', + ); + ConnectionHandler.insertEdgeAfter(notifications, edge); + }, + } +); + +//////////////////////////// +// RELAY COMPAT TESTS +/////////////////////////// +import { + QueryRenderer as CompatQueryRenderer, + createFragmentContainer as createFragmentContainerCompat +} from "react-relay/compat"; + +// TODO? This is all more or less identical to modern... + +//////////////////////////// +// 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 () { + getConfigs() { return [{ type: "RANGE_ADD", parentName: "user", @@ -34,19 +387,19 @@ export default class AddTweetMutation extends Relay.Mutation { rangeBehaviors: { "": "append", }, - }] + }]; } - getVariables () { - return this.props + getVariables() { + return this.props; } } interface ArtworkProps { artwork: { title: string - }, - relay: Relay.RelayProp, + }; + relay: Relay.RelayProp; } class Artwork extends React.Component { @@ -55,7 +408,7 @@ class Artwork extends React.Component { {this.props.artwork.title} - ) + ); } } @@ -67,7 +420,7 @@ const ArtworkContainer = Relay.createContainer(Artwork, { } ` } -}) +}); class StubbedArtwork extends React.Component { render() { @@ -83,10 +436,10 @@ class StubbedArtwork extends React.Component { setVariables: () => {}, forceFetch: () => {}, hasOptimisticUpdate: () => false, - getPendingTransactions: (): Relay.RelayMutationTransaction[] => undefined, + getPendingTransactions: (): any => undefined, commitUpdate: () => {}, } - } - return + }; + return ; } } diff --git a/types/react-relay/tsconfig.json b/types/react-relay/tsconfig.json index 90680fbafc..5447ff74ca 100644 --- a/types/react-relay/tsconfig.json +++ b/types/react-relay/tsconfig.json @@ -7,7 +7,7 @@ ], "noImplicitAny": true, "noImplicitThis": true, - "strictNullChecks": false, + "strictNullChecks": true, "baseUrl": "../", "typeRoots": [ "../" @@ -19,6 +19,10 @@ }, "files": [ "index.d.ts", - "react-relay-tests.tsx" + "react-relay-tests.tsx", + "react-relay-classic-tests.tsx", + "classic.d.ts", + "modern.d.ts", + "compat.d.ts" ] -} \ No newline at end of file +} diff --git a/types/react-relay/v1/tslint.json b/types/react-relay/tslint.json similarity index 100% rename from types/react-relay/v1/tslint.json rename to types/react-relay/tslint.json diff --git a/types/react-relay/v1/index.d.ts b/types/react-relay/v1/index.d.ts deleted file mode 100644 index e214a9a441..0000000000 --- a/types/react-relay/v1/index.d.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Type definitions for react-relay 1.3 -// Project: https://github.com/facebook/relay -// Definitions by: Johannes Schickling , Matt Martin -// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.4 - -import { RelayRuntimeTypes } from 'relay-runtime'; -import * as ReactRelayModernTypes from './lib/react-relay-modern'; - -// ~~~~~~~~~~~~~~~~~~~~~ -// React-Relay Modern -// ~~~~~~~~~~~~~~~~~~~~~ -export import QueryRenderer = ReactRelayModernTypes.ReactRelayQueryRenderer; -export import createFragmentContainer = ReactRelayModernTypes.createFragmentContainer; -export import createPaginationContainer = ReactRelayModernTypes.createPaginationContainer; -export import createRefetchContainer = ReactRelayModernTypes.createRefetchContainer; -export import graphql = ReactRelayModernTypes.graphql; -export import commitLocalUpdate = RelayRuntimeTypes.commitLocalUpdate; -export import commitMutation = RelayRuntimeTypes.commitRelayModernMutation; -export import fetchQuery = RelayRuntimeTypes.fetchRelayModernQuery; -export import requestSubscription = RelayRuntimeTypes.requestRelaySubscription; -// exported for convenience -export import ModernTypes = ReactRelayModernTypes; diff --git a/types/react-relay/v1/react-relay-tests.tsx b/types/react-relay/v1/react-relay-tests.tsx deleted file mode 100644 index 50506ac111..0000000000 --- a/types/react-relay/v1/react-relay-tests.tsx +++ /dev/null @@ -1,445 +0,0 @@ -import * as React from "react"; -import { - Environment, - Network, - RecordSource, - Store, - ConnectionHandler, -} from 'relay-runtime'; - -//////////////////////////// -// RELAY MODERN TESTS -/////////////////////////// -import { - graphql, - commitMutation, - createFragmentContainer, - createPaginationContainer, - createRefetchContainer, - requestSubscription, - QueryRenderer, - ModernTypes, -} from "react-relay"; - -// ~~~~~~~~~~~~~~~~~~~~~ -// Modern Environment -// ~~~~~~~~~~~~~~~~~~~~~ -function fetchQuery(operation: any, variables: any, cacheConfig: {}) { - return fetch('/graphql'); -} -const network = Network.create(fetchQuery); -const source = new RecordSource(); -const store = new Store(source); -const modernEnvironment = new Environment({ network, store }); - -// ~~~~~~~~~~~~~~~~~~~~~ -// Modern QueryRenderer -// ~~~~~~~~~~~~~~~~~~~~~ -const MyQueryRenderer = (props: { name: string}) => ( - { - if (error) { - return
{error.message}
; - } else if (props) { - return
{props.name} is great!
; - } - return
Loading
; - }} - /> -); - -// ~~~~~~~~~~~~~~~~~~~~~ -// 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: ModernTypes.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 => - )} -
- ); - } - - _loadMore() { - // Increments the number of stories being rendered by 10. - const refetchVariables = (fragmentVariables: {count: number }) => ({ - count: fragmentVariables.count + 10, - }); - this.props.relay.refetch(refetchVariables); - } - } - -const FeedRefetchContainer = createRefetchContainer( - FeedStories, - { - feed: graphql.experimental` - fragment FeedStories_feed on Feed - @argumentDefinitions( - count: {type: "Int", defaultValue: 10} - ) { - stories(first: $count) { - edges { - node { - id - ...Story_story - } - } - } - } - ` - }, - graphql.experimental` - query FeedStoriesRefetchQuery($count: Int) { - feed { - ...FeedStories_feed @arguments(count: $count) - } - } - `, - ); - -// ~~~~~~~~~~~~~~~~~~~~~ -// Modern PaginationContainer -// ~~~~~~~~~~~~~~~~~~~~~ -interface FeedProps { - user: { feed: { edges: Array<{ node: StoryInterface}>}}; - relay: ModernTypes.RelayPaginationProp; -} -class Feed extends React.Component { - render() { - return (
- {this.props.user.feed.edges.map( - edge => - )} -
); - } - - _loadMore() { - if (!this.props.relay.hasMore() || this.props.relay.isLoading()) { - return; - } - - this.props.relay.loadMore( - 10, // Fetch the next 10 feed items - e => { - console.log(e); - }, - ); - } -} - -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 - } - } - } - } - `, - }, - { - direction: 'forward', - getConnectionFromProps(props: { user: {feed: any}}) { - 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 - } - } - ` - } -); - -// ~~~~~~~~~~~~~~~~~~~~~ -// Modern Mutations -// ~~~~~~~~~~~~~~~~~~~~~ -const mutation = graphql` -mutation MarkReadNotificationMutation( - $input: MarkReadNotificationData! -) { - markReadNotification(data: $input) { - notification { - seenState - } - } -} -`; - -const optimisticResponse = { - markReadNotification: { - notification: { - seenState: 'SEEN', - }, - }, -}; - -const configs = [{ - type: 'NODE_DELETE' as 'NODE_DELETE', - deletedIDFieldName: 'destroyedShipId', -}, { - type: 'RANGE_ADD' as 'RANGE_ADD', - parentID: 'shipId', - connectionInfo: [{ - key: 'AddShip_ships', - rangeBehavior: 'append', - }], - edgeName: 'newShipEdge', -}, { - type: 'RANGE_DELETE' as 'RANGE_DELETE', - parentID: 'todoId', - connectionKeys: [{ - key: 'RemoveTags_tags', - rangeBehavior: 'append', - }], - pathToConnection: ['todo', 'tags'], - deletedIDFieldName: 'removedTagId' -}]; - -function markNotificationAsRead(source: string, storyID: string) { - const variables = { - input: { - source, - storyID, - }, - }; - - commitMutation( - modernEnvironment, - { - configs, - mutation, - optimisticResponse, - variables, - onCompleted: (response, errors) => { - console.log('Response received from server.'); - }, - onError: err => console.error(err), - }, - ); -} - -// ~~~~~~~~~~~~~~~~~~~~~ -// Modern Subscriptions -// ~~~~~~~~~~~~~~~~~~~~~ -const subscription = graphql` - subscription MarkReadNotificationSubscription( - $storyID: ID! - ) { - markReadNotification(storyID: $storyID) { - notification { - seenState - } - } - } -`; -const variables = { - storyID: '123', -}; -requestSubscription( - modernEnvironment, // see Environment docs - { - subscription, - variables, - // optional but recommended: - onCompleted: () => {}, - onError: error => console.error(error), - // example of a custom updater - updater: store => { - // Get the notification - const rootField = store.getRootField('markReadNotification'); - const notification = !!rootField && rootField.getLinkedRecord('notification'); - // Add it to a connection - const viewer = store.getRoot().getLinkedRecord('viewer'); - const notifications = - ConnectionHandler.getConnection(viewer, 'notifications'); - const edge = ConnectionHandler.createEdge( - store, - notifications, - notification, - '', - ); - ConnectionHandler.insertEdgeAfter(notifications, edge); - }, - } -); - -//////////////////////////// -// RELAY COMPAT TESTS -/////////////////////////// -import { - QueryRenderer as CompatQueryRenderer, - createFragmentContainer as createFragmentContainerCompat -} from "react-relay/compat"; - -// TODO? This is all more or less identical to modern... - -//////////////////////////// -// 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 ArtworkProps { - artwork: { - title: string - }; - relay: Relay.RelayProp; -} - -class Artwork extends React.Component { - render() { - return ( - - {this.props.artwork.title} - - ); - } -} - -const ArtworkContainer = Relay.createContainer(Artwork, { - fragments: { - artwork: () => Relay.QL` - fragment on Artwork { - title - } - ` - } -}); - -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/v1/tsconfig.json b/types/react-relay/v1/tsconfig.json deleted file mode 100644 index 37049aa13e..0000000000 --- a/types/react-relay/v1/tsconfig.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "lib": [ - "es6", - "dom" - ], - "noImplicitAny": true, - "noImplicitThis": true, - "strictNullChecks": true, - "baseUrl": "../../", - "typeRoots": [ - "../../" - ], - "types": [], - "noEmit": true, - "forceConsistentCasingInFileNames": true, - "jsx": "react", - "paths": { - "react-relay": ["react-relay/v1"], - "react-relay/*": ["react-relay/v1/*"], - "react-relay/classic": ["react-relay/v1/classic.d"], - "react-relay/compat": ["react-relay/v1/compat.d"] - } - }, - "files": [ - "index.d.ts", - "react-relay-tests.tsx", - "lib/react-relay-classic.d.ts", - "lib/react-relay-modern.d.ts", - "lib/react-relay-compat.d.ts" - ] -} From b438270ef30cba0eba981947fdbfdd0d579076a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 11 Oct 2017 15:15:43 +0200 Subject: [PATCH 2/7] [Relay] Reformat all files using prettier. prettier --parser typescript --tab-width 4 --semi --trailing-comma es5 \ --write --print-width 120 \ types/{react-relay,relay-runtime}/*.ts* --- types/react-relay/classic.d.ts | 91 ++--- types/react-relay/compat.d.ts | 16 +- types/react-relay/index.d.ts | 4 +- types/react-relay/modern.d.ts | 59 ++- .../react-relay/react-relay-classic-tests.tsx | 75 ++-- types/react-relay/react-relay-tests.tsx | 350 ++++++++---------- types/relay-runtime/index.d.ts | 291 +++++++-------- types/relay-runtime/relay-runtime-tests.tsx | 29 +- 8 files changed, 422 insertions(+), 493 deletions(-) diff --git a/types/react-relay/classic.d.ts b/types/react-relay/classic.d.ts index 02517b7e80..9345199d27 100644 --- a/types/react-relay/classic.d.ts +++ b/types/react-relay/classic.d.ts @@ -1,5 +1,5 @@ -import * as React from 'react'; -import { RelayCommonTypes } from 'relay-runtime'; +import * as React from "react"; +import { RelayCommonTypes } from "relay-runtime"; // ~~~~~~~~~~~~~~~~~~~~~ // Maybe Fix @@ -7,7 +7,11 @@ import { RelayCommonTypes } from 'relay-runtime'; export type StoreReaderData = any; export type StoreReaderOptions = any; export type RelayStoreData = any; -export interface RelayQuery { Fragment: any; Node: any; Root: any; } +export interface RelayQuery { + Fragment: any; + Node: any; + Root: any; +} // ~~~~~~~~~~~~~~~~~~~~~ // Environment @@ -16,33 +20,27 @@ export interface FragmentResolver { dispose(): void; resolve( fragment: RelayQuery["Fragment"], - dataIDs: RelayCommonTypes.DataID | RelayCommonTypes.DataID[], + dataIDs: RelayCommonTypes.DataID | RelayCommonTypes.DataID[] ): StoreReaderData | StoreReaderData[] | undefined | null; } export interface RelayEnvironmentInterface { forceFetch( querySet: RelayCommonTypes.RelayQuerySet, - onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback, + onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback ): RelayCommonTypes.Abortable; - getFragmentResolver( - fragment: RelayQuery["Fragment"], - onNext: () => void, - ): FragmentResolver; + getFragmentResolver(fragment: RelayQuery["Fragment"], onNext: () => void): FragmentResolver; getStoreData(): RelayStoreData; primeCache( querySet: RelayCommonTypes.RelayQuerySet, - onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback, + onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback ): RelayCommonTypes.Abortable; read( node: RelayQuery["Node"], dataID: RelayCommonTypes.DataID, - options?: StoreReaderOptions, + options?: StoreReaderOptions ): StoreReaderData | void; - readQuery( - root: RelayQuery["Root"], - options?: StoreReaderOptions, - ): StoreReaderData[] | void; + readQuery(root: RelayQuery["Root"], options?: StoreReaderOptions): StoreReaderData[] | void; } // ~~~~~~~~~~~~~~~~~~~~~ @@ -75,12 +73,12 @@ export interface RelayQueryRequestResolve { } export type RelayMutationStatus = - 'UNCOMMITTED' | // Transaction hasn't yet been sent to the server. Transaction can be committed or rolled back. - 'COMMIT_QUEUED' | // Transaction was committed but another transaction with the same collision key is pending, so the transaction has been queued to send to the server. - 'COLLISION_COMMIT_FAILED' | // Transaction was queued for commit but another transaction with the same collision key failed. All transactions in the collision queue, + | "UNCOMMITTED" // Transaction hasn't yet been sent to the server. Transaction can be committed or rolled back. + | "COMMIT_QUEUED" // Transaction was committed but another transaction with the same collision key is pending, so the transaction has been queued to send to the server. + | "COLLISION_COMMIT_FAILED" // Transaction was queued for commit but another transaction with the same collision key failed. All transactions in the collision queue, // including this one, have been failed. Transaction can be recommitted or rolled back. - 'COMMITTING' | // Transaction is waiting for the server to respond. - 'COMMIT_FAILED'; + | "COMMITTING" // Transaction is waiting for the server to respond. + | "COMMIT_FAILED"; export class RelayMutationTransaction { applyOptimistic(): RelayMutationTransaction; @@ -118,13 +116,16 @@ export class DefaultNetworkLayer implements RelayNetworkLayer { supports(...options: string[]): boolean; } -export function createContainer(component: React.ComponentClass | React.StatelessComponent, params?: CreateContainerOpts): RelayContainerClass; +export function createContainer( + component: React.ComponentClass | React.StatelessComponent, + params?: CreateContainerOpts +): RelayContainerClass; export function injectNetworkLayer(networkLayer: RelayNetworkLayer): any; export function isContainer(component: React.ComponentClass): boolean; export function QL(...args: any[]): string; export class Route { - constructor(params?: RelayVariables) + constructor(params?: RelayVariables); } /** @@ -155,7 +156,7 @@ export interface Store { export const Store: Store; -export class RootContainer extends React.Component { } +export class RootContainer extends React.Component {} export interface RootContainerProps extends React.Props { Component: RelayContainerClass; @@ -165,13 +166,13 @@ export interface RootContainerProps extends React.Props { renderFailure?(error: Error, retry: (...args: any[]) => any): JSX.Element; } -export class Renderer extends React.Component { } +export class Renderer extends React.Component {} export interface RendererProps { Container: RelayContainerClass; // Relay container that defines fragments and the view to render. forceFetch?: boolean; // Whether to send a server request regardless of data available on the client. queryConfig: Route; // `QueryConfig` or `Relay.Route` that defines the query roots. - environment: Store; // An instance of `Relay.Environment` or any object that implements the `RelayEnvironment` interface. + environment: Store; // An instance of `Relay.Environment` or any object that implements the `RelayEnvironment` interface. render?: RenderCallback; // Called to render when data requirements are being fulfilled. onReadyStateChange?: OnReadyStateChange; } @@ -186,28 +187,30 @@ export interface RenderStateConfig { export type RenderCallback = (renderState: RenderStateConfig) => any; export type ReadyStateEvent = - 'ABORT' | - 'CACHE_RESTORED_REQUIRED' | - 'CACHE_RESTORE_FAILED' | - 'CACHE_RESTORE_START' | - 'NETWORK_QUERY_ERROR' | - 'NETWORK_QUERY_RECEIVED_ALL' | - 'NETWORK_QUERY_RECEIVED_REQUIRED' | - 'NETWORK_QUERY_START' | - 'STORE_FOUND_ALL' | - 'STORE_FOUND_REQUIRED'; + | "ABORT" + | "CACHE_RESTORED_REQUIRED" + | "CACHE_RESTORE_FAILED" + | "CACHE_RESTORE_START" + | "NETWORK_QUERY_ERROR" + | "NETWORK_QUERY_RECEIVED_ALL" + | "NETWORK_QUERY_RECEIVED_REQUIRED" + | "NETWORK_QUERY_START" + | "STORE_FOUND_ALL" + | "STORE_FOUND_REQUIRED"; -export type OnReadyStateChange = (readyState: { - ready: boolean, - done: boolean, - stale: boolean, - error?: Error, - events: ReadyStateEvent[], - aborted: boolean -}) => void; +export type OnReadyStateChange = ( + readyState: { + ready: boolean; + done: boolean; + stale: boolean; + error?: Error; + events: ReadyStateEvent[]; + aborted: boolean; + } +) => void; export interface RelayProp { - readonly route: { name: string; }; // incomplete, also has params and queries + readonly route: { name: string }; // incomplete, also has params and queries readonly variables: any; readonly pendingVariables?: any; setVariables(variables: any, onReadyStateChange?: OnReadyStateChange): void; diff --git a/types/react-relay/compat.d.ts b/types/react-relay/compat.d.ts index e16bbb01f9..74f7f55a03 100644 --- a/types/react-relay/compat.d.ts +++ b/types/react-relay/compat.d.ts @@ -1,6 +1,6 @@ -import { RelayRuntimeTypes, RelayCommonTypes } from 'relay-runtime'; -import { RelayEnvironmentInterface } from 'react-relay/classic'; -import {} from 'react-relay/modern'; +import { RelayRuntimeTypes, RelayCommonTypes } from "relay-runtime"; +import { RelayEnvironmentInterface } from "react-relay/classic"; +import {} from "react-relay/modern"; // ~~~~~~~~~~~~~~~~~~~~~ // Maybe Fix @@ -34,20 +34,22 @@ export type CompatEnvironment = RelayRuntimeTypes.Environment | RelayClassicEnvi // ~~~~~~~~~~~~~~~~~~~~~ export function commitUpdate( environment: CompatEnvironment, - config: RelayRuntimeTypes.MutationConfig, + config: RelayRuntimeTypes.MutationConfig ): RelayCommonTypes.Disposable; export function applyUpdate( environment: CompatEnvironment, - config: RelayRuntimeTypes.OptimisticMutationConfig, + config: RelayRuntimeTypes.OptimisticMutationConfig ): RelayCommonTypes.Disposable; // ~~~~~~~~~~~~~~~~~~~~~ // RelayCompatContainer // ~~~~~~~~~~~~~~~~~~~~~ -export interface GeneratedNodeMap { [key: string]: RelayCommonTypes.GraphQLTaggedNode; } +export interface GeneratedNodeMap { + [key: string]: RelayCommonTypes.GraphQLTaggedNode; +} export function createContainer( Component: ReactBaseComponent, - fragmentSpec: RelayCommonTypes.GraphQLTaggedNode | GeneratedNodeMap, + fragmentSpec: RelayCommonTypes.GraphQLTaggedNode | GeneratedNodeMap ): ReactFragmentComponent; // ~~~~~~~~~~~~~~~~~~~~~ diff --git a/types/react-relay/index.d.ts b/types/react-relay/index.d.ts index 72a661e6b7..30cb29b3e3 100644 --- a/types/react-relay/index.d.ts +++ b/types/react-relay/index.d.ts @@ -4,8 +4,8 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.4 -import { RelayRuntimeTypes } from 'relay-runtime'; -import * as ReactRelayModernTypes from 'react-relay/modern'; +import { RelayRuntimeTypes } from "relay-runtime"; +import * as ReactRelayModernTypes from "react-relay/modern"; // ~~~~~~~~~~~~~~~~~~~~~ // React-Relay Modern diff --git a/types/react-relay/modern.d.ts b/types/react-relay/modern.d.ts index f6d1eb0381..13b43bf449 100644 --- a/types/react-relay/modern.d.ts +++ b/types/react-relay/modern.d.ts @@ -1,5 +1,5 @@ -import * as React from 'react'; -import { RelayCommonTypes, RelayRuntimeTypes } from 'relay-runtime'; +import * as React from "react"; +import { RelayCommonTypes, RelayRuntimeTypes } from "relay-runtime"; // ~~~~~~~~~~~~~~~~~~~~~ // Maybe Fix @@ -21,23 +21,20 @@ export interface RelayProp { // ~~~~~~~~~~~~~~~~~~~~~ // RelayQL // ~~~~~~~~~~~~~~~~~~~~~ -export function RelayQL( - strings: string[], - ...substitutions: any[] -): RelayCommonTypes.RelayConcreteNode; +export function RelayQL(strings: string[], ...substitutions: any[]): RelayCommonTypes.RelayConcreteNode; // ~~~~~~~~~~~~~~~~~~~~~ // RelayModernGraphQLTag // ~~~~~~~~~~~~~~~~~~~~~ -export interface GeneratedNodeMap { [key: string]: GraphQLTaggedNode; } +export interface GeneratedNodeMap { + [key: string]: GraphQLTaggedNode; +} export type GraphQLTaggedNode = - (() => ConcreteFragment | ConcreteBatch) + | (() => ConcreteFragment | ConcreteBatch) | { - modern(): ConcreteFragment | ConcreteBatch, - classic(relayQL: typeof RelayQL): - | ConcreteFragmentDefinition - | ConcreteOperationDefinition, - }; + 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. @@ -67,14 +64,14 @@ export interface ReadyState { export interface QueryRendererState { readyState: ReadyState; } -export class ReactRelayQueryRenderer extends React.Component { } +export class ReactRelayQueryRenderer extends React.Component {} // ~~~~~~~~~~~~~~~~~~~~~ // createFragmentContainer // ~~~~~~~~~~~~~~~~~~~~~ export function createFragmentContainer( Component: ReactBaseComponent, - fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, + fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap ): ReactBaseComponent; // ~~~~~~~~~~~~~~~~~~~~~ @@ -91,38 +88,38 @@ export interface ConnectionData { pageInfo?: PageInfo; } export type RelayPaginationProp = RelayProp & { - hasMore(): boolean, - isLoading(): boolean, + hasMore(): boolean; + isLoading(): boolean; loadMore( pageSize: number, callback: (error?: Error) => void, - options?: RefetchOptions, - ): RelayCommonTypes.Disposable | undefined | null, + options?: RefetchOptions + ): RelayCommonTypes.Disposable | undefined | null; refetchConnection( totalCount: number, callback: (error?: Error) => void, - refetchVariables?: RelayCommonTypes.Variables, - ): RelayCommonTypes.Disposable | undefined | null, + refetchVariables?: RelayCommonTypes.Variables + ): RelayCommonTypes.Disposable | undefined | null; }; export function FragmentVariablesGetter( prevVars: RelayCommonTypes.Variables, - totalCount: number, + totalCount: number ): RelayCommonTypes.Variables; export interface ConnectionConfig { - direction?: 'backward' | 'forward'; + direction?: "backward" | "forward"; getConnectionFromProps?(props: object): ConnectionData | undefined | null; getFragmentVariables?: typeof FragmentVariablesGetter; getVariables( props: { [propName: string]: any }, - paginationInfo: { count: number, cursor?: string }, - fragmentVariables: RelayCommonTypes.Variables, + paginationInfo: { count: number; cursor?: string }, + fragmentVariables: RelayCommonTypes.Variables ): RelayCommonTypes.Variables; query: GraphQLTaggedNode; } export function createPaginationContainer( Component: ReactBaseComponent, fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, - connectionConfig: ConnectionConfig, + connectionConfig: ConnectionConfig ): ReactBaseComponent; // ~~~~~~~~~~~~~~~~~~~~~ @@ -134,14 +131,16 @@ export interface RefetchOptions { } export type RelayRefetchProp = RelayProp & { refetch( - refetchVariables: RelayCommonTypes.Variables | ((fragmentVariables: RelayCommonTypes.Variables) => RelayCommonTypes.Variables), + refetchVariables: + | RelayCommonTypes.Variables + | ((fragmentVariables: RelayCommonTypes.Variables) => RelayCommonTypes.Variables), renderVariables?: RelayCommonTypes.Variables, callback?: (error?: Error) => void, - options?: RefetchOptions, - ): RelayCommonTypes.Disposable, + options?: RefetchOptions + ): RelayCommonTypes.Disposable; }; export function createRefetchContainer( Component: ReactBaseComponent, fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, - taggedNode: GraphQLTaggedNode, + taggedNode: GraphQLTaggedNode ): ReactBaseComponent; diff --git a/types/react-relay/react-relay-classic-tests.tsx b/types/react-relay/react-relay-classic-tests.tsx index b7531598eb..7aae267dfc 100644 --- a/types/react-relay/react-relay-classic-tests.tsx +++ b/types/react-relay/react-relay-classic-tests.tsx @@ -1,61 +1,58 @@ -import * as React from "react" -import * as Relay from "react-relay/classic" +import * as React from "react"; +import * as Relay from "react-relay/classic"; interface Props { - text: string - userId: string + text: string; + userId: string; } -interface Response { -} +// tslint:disable-next-line no-empty-interface +interface Response {} export default class AddTweetMutation extends Relay.Mutation { - - getMutation () { - return Relay.QL`mutation{addTweet}` + getMutation() { + return Relay.QL`mutation{addTweet}`; } - getFatQuery () { + 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", + getConfigs() { + return [ + { + type: "RANGE_ADD", + parentName: "user", + parentID: this.props.userId, + connectionName: "tweets", + edgeName: "tweetEdge", + rangeBehaviors: { + "": "append", + }, }, - }] + ]; } - getVariables () { - return this.props + getVariables() { + return this.props; } } interface ArtworkProps { artwork: { - title: string - }, - relay: Relay.RelayProp, + title: string; + }; + relay: Relay.RelayProp; } class Artwork extends React.Component { render() { - return ( - - {this.props.artwork.title} - - ) + return {this.props.artwork.title}; } } @@ -65,9 +62,9 @@ const ArtworkContainer = Relay.createContainer(Artwork, { fragment on Artwork { title } - ` - } -}) + `, + }, +}); class StubbedArtwork extends React.Component { render() { @@ -75,7 +72,7 @@ class StubbedArtwork extends React.Component { artwork: { title: "CHAMPAGNE FORMICA FLAG" }, relay: { route: { - name: "champagne" + name: "champagne", }, variables: { artworkID: "champagne-formica-flag", @@ -83,10 +80,10 @@ class StubbedArtwork extends React.Component { setVariables: () => {}, forceFetch: () => {}, hasOptimisticUpdate: () => false, - getPendingTransactions: (): Relay.RelayMutationTransaction[] => undefined, + getPendingTransactions: (): Relay.RelayMutationTransaction[] => [], commitUpdate: () => {}, - } - } - return + }, + }; + return ; } } diff --git a/types/react-relay/react-relay-tests.tsx b/types/react-relay/react-relay-tests.tsx index 50506ac111..97cc5d47d9 100644 --- a/types/react-relay/react-relay-tests.tsx +++ b/types/react-relay/react-relay-tests.tsx @@ -1,11 +1,5 @@ import * as React from "react"; -import { - Environment, - Network, - RecordSource, - Store, - ConnectionHandler, -} from 'relay-runtime'; +import { Environment, Network, RecordSource, Store, ConnectionHandler } from "relay-runtime"; //////////////////////////// // RELAY MODERN TESTS @@ -25,7 +19,7 @@ import { // Modern Environment // ~~~~~~~~~~~~~~~~~~~~~ function fetchQuery(operation: any, variables: any, cacheConfig: {}) { - return fetch('/graphql'); + return fetch("/graphql"); } const network = Network.create(fetchQuery); const source = new RecordSource(); @@ -35,28 +29,28 @@ const modernEnvironment = new Environment({ network, store }); // ~~~~~~~~~~~~~~~~~~~~~ // Modern QueryRenderer // ~~~~~~~~~~~~~~~~~~~~~ -const MyQueryRenderer = (props: { name: string}) => ( - { - if (error) { - return
{error.message}
; - } else if (props) { - return
{props.name} is great!
; - } - return
Loading
; - }} - /> +const MyQueryRenderer = (props: { name: string }) => ( + { + if (error) { + return
{error.message}
; + } else if (props) { + return
{props.name} is great!
; + } + return
Loading
; + }} + /> ); // ~~~~~~~~~~~~~~~~~~~~~ @@ -65,14 +59,14 @@ const MyQueryRenderer = (props: { name: string}) => ( const MyFragmentContainer = createFragmentContainer( class TodoListView extends React.Component { render() { - return
; + return
; } }, { item: graphql` fragment TodoItem_item on Todo { - text - isComplete + text + isComplete } `, } @@ -81,84 +75,75 @@ const MyFragmentContainer = createFragmentContainer( // ~~~~~~~~~~~~~~~~~~~~~ // Modern RefetchContainer // ~~~~~~~~~~~~~~~~~~~~~ -interface StoryInterface { id: string; } +interface StoryInterface { + id: string; +} interface FeedStoriesProps { relay: ModernTypes.RelayRefetchProp; feed: { - stories: { edges: Array<{ node: StoryInterface }> } + 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 => - )} -
- ); + return ( +
+ {this.props.feed.stories.edges.map(edge => )} +
+ ); } _loadMore() { - // Increments the number of stories being rendered by 10. - const refetchVariables = (fragmentVariables: {count: number }) => ({ - count: fragmentVariables.count + 10, - }); - this.props.relay.refetch(refetchVariables); + // Increments the number of stories being rendered by 10. + const refetchVariables = (fragmentVariables: { count: number }) => ({ + count: fragmentVariables.count + 10, + }); + this.props.relay.refetch(refetchVariables); } - } +} const FeedRefetchContainer = createRefetchContainer( FeedStories, { - feed: graphql.experimental` - fragment FeedStories_feed on Feed - @argumentDefinitions( - count: {type: "Int", defaultValue: 10} - ) { - stories(first: $count) { - edges { - node { - id - ...Story_story - } + feed: graphql.experimental` + fragment FeedStories_feed on Feed @argumentDefinitions(count: { type: "Int", defaultValue: 10 }) { + stories(first: $count) { + edges { + node { + id + ...Story_story + } + } + } } - } - } - ` + `, }, graphql.experimental` - query FeedStoriesRefetchQuery($count: Int) { - feed { - ...FeedStories_feed @arguments(count: $count) + query FeedStoriesRefetchQuery($count: Int) { + feed { + ...FeedStories_feed @arguments(count: $count) + } } - } - `, - ); + ` +); // ~~~~~~~~~~~~~~~~~~~~~ // Modern PaginationContainer // ~~~~~~~~~~~~~~~~~~~~~ interface FeedProps { - user: { feed: { edges: Array<{ node: StoryInterface}>}}; + user: { feed: { edges: Array<{ node: StoryInterface }> } }; relay: ModernTypes.RelayPaginationProp; } class Feed extends React.Component { render() { - return (
- {this.props.user.feed.edges.map( - edge => - )} -
); + return ( +
+ {this.props.user.feed.edges.map(edge => )} +
+ ); } _loadMore() { @@ -170,7 +155,7 @@ class Feed extends React.Component { 10, // Fetch the next 10 feed items e => { console.log(e); - }, + } ); } } @@ -179,25 +164,25 @@ 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 + fragment Feed_user on User { + feed( + first: $count + after: $cursor + orderby: $orderBy # other variables + ) @connection(key: "Feed_feed") { + edges { + node { + id + ...Story_story + } + } } } - } - } `, }, { - direction: 'forward', - getConnectionFromProps(props: { user: {feed: any}}) { + direction: "forward", + getConnectionFromProps(props: { user: { feed: any } }) { return props.user && props.user.feed; }, getFragmentVariables(prevVars, totalCount) { @@ -206,7 +191,7 @@ const FeedPaginationContainer = createPaginationContainer( count: totalCount, }; }, - getVariables(props, {count, cursor}, fragmentVariables) { + getVariables(props, { count, cursor }, fragmentVariables) { return { count, cursor, @@ -216,17 +201,13 @@ const FeedPaginationContainer = createPaginationContainer( }; }, query: graphql` - query FeedPaginationQuery( - $count: Int! - $cursor: String - $orderby: String! - ) { - user { - # You could reference the fragment defined previously. - ...Feed_user + query FeedPaginationQuery($count: Int!, $cursor: String, $orderby: String!) { + user { + # You could reference the fragment defined previously. + ...Feed_user + } } - } - ` + `, } ); @@ -234,46 +215,52 @@ const FeedPaginationContainer = createPaginationContainer( // Modern Mutations // ~~~~~~~~~~~~~~~~~~~~~ const mutation = graphql` -mutation MarkReadNotificationMutation( - $input: MarkReadNotificationData! -) { - markReadNotification(data: $input) { - notification { - seenState + mutation MarkReadNotificationMutation($input: MarkReadNotificationData!) { + markReadNotification(data: $input) { + notification { + seenState + } } } -} `; const optimisticResponse = { markReadNotification: { notification: { - seenState: 'SEEN', + seenState: "SEEN", }, }, }; -const configs = [{ - type: 'NODE_DELETE' as 'NODE_DELETE', - deletedIDFieldName: 'destroyedShipId', -}, { - type: 'RANGE_ADD' as 'RANGE_ADD', - parentID: 'shipId', - connectionInfo: [{ - key: 'AddShip_ships', - rangeBehavior: 'append', - }], - edgeName: 'newShipEdge', -}, { - type: 'RANGE_DELETE' as 'RANGE_DELETE', - parentID: 'todoId', - connectionKeys: [{ - key: 'RemoveTags_tags', - rangeBehavior: 'append', - }], - pathToConnection: ['todo', 'tags'], - deletedIDFieldName: 'removedTagId' -}]; +const configs = [ + { + type: "NODE_DELETE" as "NODE_DELETE", + deletedIDFieldName: "destroyedShipId", + }, + { + type: "RANGE_ADD" as "RANGE_ADD", + parentID: "shipId", + connectionInfo: [ + { + key: "AddShip_ships", + rangeBehavior: "append", + }, + ], + edgeName: "newShipEdge", + }, + { + type: "RANGE_DELETE" as "RANGE_DELETE", + parentID: "todoId", + connectionKeys: [ + { + key: "RemoveTags_tags", + rangeBehavior: "append", + }, + ], + pathToConnection: ["todo", "tags"], + deletedIDFieldName: "removedTagId", + }, +]; function markNotificationAsRead(source: string, storyID: string) { const variables = { @@ -283,37 +270,32 @@ function markNotificationAsRead(source: string, storyID: string) { }, }; - commitMutation( - modernEnvironment, - { - configs, - mutation, - optimisticResponse, - variables, - onCompleted: (response, errors) => { - console.log('Response received from server.'); - }, - onError: err => console.error(err), + commitMutation(modernEnvironment, { + configs, + mutation, + optimisticResponse, + variables, + onCompleted: (response, errors) => { + console.log("Response received from server."); }, - ); + onError: err => console.error(err), + }); } // ~~~~~~~~~~~~~~~~~~~~~ // Modern Subscriptions // ~~~~~~~~~~~~~~~~~~~~~ const subscription = graphql` - subscription MarkReadNotificationSubscription( - $storyID: ID! - ) { - markReadNotification(storyID: $storyID) { - notification { - seenState + subscription MarkReadNotificationSubscription($storyID: ID!) { + markReadNotification(storyID: $storyID) { + notification { + seenState + } } } - } `; const variables = { - storyID: '123', + storyID: "123", }; requestSubscription( modernEnvironment, // see Environment docs @@ -326,18 +308,12 @@ requestSubscription( // example of a custom updater updater: store => { // Get the notification - const rootField = store.getRootField('markReadNotification'); - const notification = !!rootField && rootField.getLinkedRecord('notification'); + const rootField = store.getRootField("markReadNotification"); + const notification = !!rootField && rootField.getLinkedRecord("notification"); // Add it to a connection - const viewer = store.getRoot().getLinkedRecord('viewer'); - const notifications = - ConnectionHandler.getConnection(viewer, 'notifications'); - const edge = ConnectionHandler.createEdge( - store, - notifications, - notification, - '', - ); + const viewer = store.getRoot().getLinkedRecord("viewer"); + const notifications = ConnectionHandler.getConnection(viewer, "notifications"); + const edge = ConnectionHandler.createEdge(store, notifications, notification, ""); ConnectionHandler.insertEdgeAfter(notifications, edge); }, } @@ -348,7 +324,7 @@ requestSubscription( /////////////////////////// import { QueryRenderer as CompatQueryRenderer, - createFragmentContainer as createFragmentContainerCompat + createFragmentContainer as createFragmentContainerCompat, } from "react-relay/compat"; // TODO? This is all more or less identical to modern... @@ -378,16 +354,18 @@ export default class AddTweetMutation extends Relay.Mutation { } getConfigs() { - return [{ - type: "RANGE_ADD", - parentName: "user", - parentID: this.props.userId, - connectionName: "tweets", - edgeName: "tweetEdge", - rangeBehaviors: { - "": "append", + return [ + { + type: "RANGE_ADD", + parentName: "user", + parentID: this.props.userId, + connectionName: "tweets", + edgeName: "tweetEdge", + rangeBehaviors: { + "": "append", + }, }, - }]; + ]; } getVariables() { @@ -397,18 +375,14 @@ export default class AddTweetMutation extends Relay.Mutation { interface ArtworkProps { artwork: { - title: string + title: string; }; relay: Relay.RelayProp; } class Artwork extends React.Component { render() { - return ( - - {this.props.artwork.title} - - ); + return {this.props.artwork.title}; } } @@ -418,8 +392,8 @@ const ArtworkContainer = Relay.createContainer(Artwork, { fragment on Artwork { title } - ` - } + `, + }, }); class StubbedArtwork extends React.Component { @@ -428,7 +402,7 @@ class StubbedArtwork extends React.Component { artwork: { title: "CHAMPAGNE FORMICA FLAG" }, relay: { route: { - name: "champagne" + name: "champagne", }, variables: { artworkID: "champagne-formica-flag", @@ -438,7 +412,7 @@ class StubbedArtwork extends React.Component { hasOptimisticUpdate: () => false, getPendingTransactions: (): any => undefined, commitUpdate: () => {}, - } + }, }; return ; } diff --git a/types/relay-runtime/index.d.ts b/types/relay-runtime/index.d.ts index 152df90640..88abec0a9b 100644 --- a/types/relay-runtime/index.d.ts +++ b/types/relay-runtime/index.d.ts @@ -36,10 +36,7 @@ export namespace RelayCommonTypes { // ~~~~~~~~~~~~~~~~~~~~~ // RelayQL // ~~~~~~~~~~~~~~~~~~~~~ - type RelayQL = ( - strings: string[], - ...substitutions: any[] - ) => RelayConcreteNode; + type RelayQL = (strings: string[], ...substitutions: any[]) => RelayConcreteNode; // ~~~~~~~~~~~~~~~~~~~~~ // RelayModernGraphQLTag @@ -48,13 +45,11 @@ export namespace RelayCommonTypes { [key: string]: GraphQLTaggedNode; } type GraphQLTaggedNode = - (() => ConcreteFragment | ConcreteBatch) | - { - modern(): ConcreteFragment | ConcreteBatch, - classic(relayQL: RelayQL): - | ConcreteFragmentDefinition - | ConcreteOperationDefinition, - }; + | (() => ConcreteFragment | ConcreteBatch) + | { + modern(): ConcreteFragment | ConcreteBatch; + classic(relayQL: RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition; + }; // ~~~~~~~~~~~~~~~~~~~~~ // General Usage // ~~~~~~~~~~~~~~~~~~~~~ @@ -81,8 +76,8 @@ export namespace RelayCommonTypes { interface PayloadError { message: string; locations?: Array<{ - line: number, - column: number, + line: number; + column: number; }>; } /** @@ -94,7 +89,7 @@ export namespace RelayCommonTypes { operation: ConcreteBatch, variables: Variables, cacheConfig: CacheConfig, - uploadables?: UploadableMap, + uploadables?: UploadableMap ): Runtime.ObservableFromValue; /** @@ -108,7 +103,7 @@ export namespace RelayCommonTypes { operation: ConcreteBatch, variables: Variables, cacheConfig: CacheConfig, - observer: LegacyObserver, + observer: LegacyObserver ) => Runtime.RelayObservable | Disposable; // ~~~~~~~~~~~~~~~~~~~~~ @@ -131,7 +126,7 @@ export namespace RelayCommonTypes { store: RecordSourceSelectorProxy, // Actually RelayCombinedEnvironmentTypes#SelectorData, but mixed is // inconvenient to access deeply in product code. - data: any, // FLOW FIXME + data: any // FLOW FIXME ) => void; /** @@ -152,22 +147,14 @@ export namespace RelayCommonTypes { getDataID(): DataID; getLinkedRecord(name: string, args?: Variables): RecordProxy | void; getLinkedRecords(name: string, args?: Variables): Array | void; - getOrCreateLinkedRecord( - name: string, - typeName: string, - args?: Variables, - ): RecordProxy; + getOrCreateLinkedRecord(name: string, typeName: string, args?: Variables): RecordProxy; getType(): string; getValue(name: string, args?: Variables): any; - setLinkedRecord( - record: RecordProxy, - name: string, - args?: Variables, - ): RecordProxy; + setLinkedRecord(record: RecordProxy, name: string, args?: Variables): RecordProxy; setLinkedRecords( records: Array | undefined | null, name: string, - args?: Variables, + args?: Variables ): RecordProxy; setValue(value: any, name: string, args?: Variables): RecordProxy; } @@ -228,17 +215,23 @@ export namespace RelayCommonTypes { /** * Arbitrary data e.g. received by a container as props. */ - interface Props { [key: string]: any; } + interface Props { + [key: string]: any; + } /* * An individual cached graph object. */ - interface Record { [key: string]: any; } + interface Record { + [key: string]: any; + } /** * A collection of records keyed by id. */ - interface RecordMap { [dataID: string]: Record | null | undefined; } + interface RecordMap { + [dataID: string]: Record | null | undefined; + } /** * A selector defines the starting point for a traversal into the graph for the @@ -254,20 +247,24 @@ export namespace RelayCommonTypes { * A representation of a selector and its results at a particular point in time. */ type CSnapshot = CSelector & { - data: SelectorData | null | undefined, - seenRecords: RecordMap, + data: SelectorData | null | undefined; + seenRecords: RecordMap; }; /** * The results of a selector given a store/RecordSource. */ - interface SelectorData { [key: string]: any; } + interface SelectorData { + [key: string]: any; + } /** * The results of reading the results of a FragmentMap given some input * `Props`. */ - interface FragmentSpecResults { [key: string]: any; } + interface FragmentSpecResults { + [key: string]: any; + } /** * A utility for resolving and subscribing to the results of a fragment spec @@ -304,7 +301,9 @@ export namespace RelayCommonTypes { setVariables(variables: Variables): void; } - interface CFragmentMap { [key: string]: TFragment; } + interface CFragmentMap { + [key: string]: TFragment; + } /** * An operation selector describes a specific instance of a GraphQL operation @@ -326,14 +325,7 @@ export namespace RelayCommonTypes { * The public API of Relay core. Represents an encapsulated environment with its * own in-memory cache. */ - interface CEnvironment< - TEnvironment, - TFragment, - TGraphQLTaggedNode, - TNode, - TOperation, - TPayload, - > { + interface CEnvironment { /** * Read the results of a selector from in-memory records in the store. */ @@ -344,10 +336,7 @@ export namespace RelayCommonTypes { * when data has been committed to the store that would cause the results of * the snapshot's selector to change. */ - subscribe( - snapshot: CSnapshot, - callback: (snapshot: CSnapshot) => void, - ): Disposable; + subscribe(snapshot: CSnapshot, callback: (snapshot: CSnapshot) => void): Disposable; /** * Ensure that all the records necessary to fulfill the given selector are @@ -370,11 +359,11 @@ export namespace RelayCommonTypes { * after receving the first `onNext` result. */ sendQuery(config: { - cacheConfig?: CacheConfig, - onCompleted?(): void, - onError?(error: Error): void, - onNext?(payload: TPayload): void, - operation: COperationSelector, + cacheConfig?: CacheConfig; + onCompleted?(): void; + onError?(error: Error): void; + onNext?(payload: TPayload): void; + operation: COperationSelector; }): Disposable; /** @@ -386,29 +375,17 @@ export namespace RelayCommonTypes { * subscription open indefinitely such that `onCompleted` is not called. */ streamQuery(config: { - cacheConfig?: CacheConfig, - onCompleted?(): void, - onError?(error: Error): void, - onNext?(payload: TPayload): void, - operation: COperationSelector, + cacheConfig?: CacheConfig; + onCompleted?(): void; + onError?(error: Error): void; + onNext?(payload: TPayload): void; + operation: COperationSelector; }): Disposable; - unstable_internal: CUnstableEnvironmentCore< - TEnvironment, - TFragment, - TGraphQLTaggedNode, - TNode, - TOperation - >; + unstable_internal: CUnstableEnvironmentCore; } - interface CUnstableEnvironmentCore< - TEnvironment, - TFragment, - TGraphQLTaggedNode, - TNode, - TOperation, - > { + interface CUnstableEnvironmentCore { /** * Create an instance of a FragmentSpecResolver. * @@ -421,7 +398,7 @@ export namespace RelayCommonTypes { containerName: string, fragments: CFragmentMap, props: Props, - callback: () => void, + callback: () => void ): FragmentSpecResolver; /** @@ -430,10 +407,7 @@ export namespace RelayCommonTypes { * filtered to exclude variables that do not matche defined arguments on the * operation, and default values are populated for null values. */ - createOperationSelector( - operation: TOperation, - variables: Variables, - ): COperationSelector; + createOperationSelector(operation: TOperation, variables: Variables): COperationSelector; /** * Given a graphql`...` tagged template, extract a fragment definition usable @@ -482,11 +456,7 @@ export namespace RelayCommonTypes { * const childData = environment.lookup(childSelector).data; * ``` */ - getSelector( - operationVariables: Variables, - fragment: TFragment, - prop: any, - ): CSelector | void; + getSelector(operationVariables: Variables, fragment: TFragment, prop: any): CSelector | void; /** * Given the result `items` from a parent that fetched `fragment`, creates a @@ -497,7 +467,7 @@ export namespace RelayCommonTypes { getSelectorList( operationVariables: Variables, fragment: TFragment, - props: any[], + props: any[] ): Array> | void; /** @@ -511,7 +481,7 @@ export namespace RelayCommonTypes { getSelectorsFromObject( operationVariables: Variables, fragments: CFragmentMap, - props: Props, + props: Props ): { [key: string]: CSelector | Array> | null | undefined }; /** @@ -523,7 +493,7 @@ export namespace RelayCommonTypes { */ getDataIDsFromObject( fragments: CFragmentMap, - props: Props, + props: Props ): { [key: string]: DataID | DataID[] | null | undefined }; /** @@ -537,7 +507,7 @@ export namespace RelayCommonTypes { getVariablesFromObject( operationVariables: Variables, fragments: CFragmentMap, - props: Props, + props: Props ): Variables; } @@ -564,51 +534,46 @@ export namespace RelayCommonTypes { max_runs: number; } interface FIELDS_CHANGE { - type: 'FIELDS_CHANGE'; - fieldIDs: { [fieldName: string]: DataID | DataID[]; }; + type: "FIELDS_CHANGE"; + fieldIDs: { [fieldName: string]: DataID | DataID[] }; } interface RANGE_ADD { - type: 'RANGE_ADD'; + type: "RANGE_ADD"; parentName?: string; parentID?: string; connectionInfo?: Array<{ - key: string, - filters?: Variables, - rangeBehavior: string, + key: string; + filters?: Variables; + rangeBehavior: string; }>; connectionName?: string; edgeName: string; rangeBehaviors?: RangeBehaviors; } interface NODE_DELETE { - type: 'NODE_DELETE'; + type: "NODE_DELETE"; parentName?: string; parentID?: string; connectionName?: string; deletedIDFieldName: string; } interface RANGE_DELETE { - type: 'RANGE_DELETE'; + type: "RANGE_DELETE"; parentName?: string; parentID?: string; connectionKeys?: Array<{ - key: string, - filters?: Variables, + key: string; + filters?: Variables; }>; connectionName?: string; deletedIDFieldName: string | string[]; pathToConnection: string[]; } interface REQUIRED_CHILDREN { - type: 'REQUIRED_CHILDREN'; + type: "REQUIRED_CHILDREN"; children: RelayConcreteNode[]; } - type RelayMutationConfig = - FIELDS_CHANGE | - RANGE_ADD | - NODE_DELETE | - RANGE_DELETE | - REQUIRED_CHILDREN; + type RelayMutationConfig = FIELDS_CHANGE | RANGE_ADD | NODE_DELETE | RANGE_DELETE | REQUIRED_CHILDREN; interface RelayMutationTransactionCommitCallbacks { onFailure?: RelayMutationTransactionCommitFailureCallback; @@ -616,11 +581,13 @@ export namespace RelayCommonTypes { } type RelayMutationTransactionCommitFailureCallback = ( transaction: RelayMutationTransaction, - preventAutoRollback: () => void, + preventAutoRollback: () => void + ) => void; + type RelayMutationTransactionCommitSuccessCallback = ( + response: { + [key: string]: any; + } ) => void; - type RelayMutationTransactionCommitSuccessCallback = (response: { - [key: string]: any, - }) => void; interface NetworkLayer { sendMutation(request: RelayMutationRequest): Promise | void; sendQueries(requests: RelayQueryRequest[]): Promise | void; @@ -639,18 +606,16 @@ export namespace RelayCommonTypes { ready: boolean; stale: boolean; } - type RelayContainerErrorEventType = - | 'CACHE_RESTORE_FAILED' - | 'NETWORK_QUERY_ERROR'; + type RelayContainerErrorEventType = "CACHE_RESTORE_FAILED" | "NETWORK_QUERY_ERROR"; type RelayContainerLoadingEventType = - | 'ABORT' - | 'CACHE_RESTORED_REQUIRED' - | 'CACHE_RESTORE_START' - | 'NETWORK_QUERY_RECEIVED_ALL' - | 'NETWORK_QUERY_RECEIVED_REQUIRED' - | 'NETWORK_QUERY_START' - | 'STORE_FOUND_ALL' - | 'STORE_FOUND_REQUIRED'; + | "ABORT" + | "CACHE_RESTORED_REQUIRED" + | "CACHE_RESTORE_START" + | "NETWORK_QUERY_RECEIVED_ALL" + | "NETWORK_QUERY_RECEIVED_REQUIRED" + | "NETWORK_QUERY_START" + | "STORE_FOUND_ALL" + | "STORE_FOUND_REQUIRED"; type ReadyStateChangeCallback = (readyState: ReadyState) => void; interface ReadyStateEvent { type: RelayContainerLoadingEventType | RelayContainerErrorEventType; @@ -668,13 +633,19 @@ export namespace RelayCommonTypes { * https://github.com/facebook/relay/blob/master/packages/react-relay/classic/tools/RelayInternalTypes.js */ // ~~~~~~~~~~~~~~~~~~~~~ - interface QueryPayload { [key: string]: any; } - interface RelayQuerySet { [queryName: string]: any; } - type RangeBehaviorsFunction = (connectionArgs: { - [argName: string]: any, - }) => 'APPEND' | 'IGNORE' | 'PREPEND' | 'REFETCH' | 'REMOVE'; + interface QueryPayload { + [key: string]: any; + } + interface RelayQuerySet { + [queryName: string]: any; + } + type RangeBehaviorsFunction = ( + connectionArgs: { + [argName: string]: any; + } + ) => "APPEND" | "IGNORE" | "PREPEND" | "REFETCH" | "REMOVE"; interface RangeBehaviorsObject { - [key: string]: 'APPEND' | 'IGNORE' | 'PREPEND' | 'REFETCH' | 'REMOVE'; + [key: string]: "APPEND" | "IGNORE" | "PREPEND" | "REFETCH" | "REMOVE"; } type RangeBehaviors = RangeBehaviorsFunction | RangeBehaviorsObject; } @@ -700,7 +671,7 @@ export namespace RelayRuntimeTypes { operation: object, variables: RelayCommonTypes.Variables, cacheConfig: RelayCommonTypes.CacheConfig, - uploadables?: RelayCommonTypes.UploadableMap, + uploadables?: RelayCommonTypes.UploadableMap ) => Promise; interface RelayNetwork { execute: ExecuteFunction; @@ -728,41 +699,39 @@ export namespace RelayRuntimeTypes { revertUpdate(update: OptimisticUpdate): void; replaceUpdate(update: OptimisticUpdate, newUpdate: OptimisticUpdate): void; applyMutation(config: { - operation: OperationSelector, - optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater, - optimisticResponse?: object, + operation: OperationSelector; + optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater; + optimisticResponse?: object; }): RelayCommonTypes.Disposable; check(readSelector: Selector): boolean; - commitPayload( - operationSelector: OperationSelector, - payload: PayloadData, - ): void; + commitPayload(operationSelector: OperationSelector, payload: PayloadData): void; commitUpdate(updater: RelayCommonTypes.StoreUpdater): void; lookup(readSelector: Selector): Snapshot; - subscribe( - snapshot: Snapshot, - callback: (snapshot: Snapshot) => void, - ): RelayCommonTypes.Disposable; + subscribe(snapshot: Snapshot, callback: (snapshot: Snapshot) => void): RelayCommonTypes.Disposable; retain(selector: Selector): RelayCommonTypes.Disposable; execute(config: { - operation: OperationSelector, - cacheConfig?: RelayCommonTypes.CacheConfig, - updater?: RelayCommonTypes.SelectorStoreUpdater, + operation: OperationSelector; + cacheConfig?: RelayCommonTypes.CacheConfig; + updater?: RelayCommonTypes.SelectorStoreUpdater; }): RelayObservable; executeMutation(config: { - operation: OperationSelector, - optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater, - optimisticResponse?: object, - updater?: RelayCommonTypes.SelectorStoreUpdater, - uploadables?: RelayCommonTypes.UploadableMap, + operation: OperationSelector; + optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater; + optimisticResponse?: object; + updater?: RelayCommonTypes.SelectorStoreUpdater; + uploadables?: RelayCommonTypes.UploadableMap; }): RelayObservable; } // ~~~~~~~~~~~~~~~~~~~~~ // RelayInMemoryRecordSource // ~~~~~~~~~~~~~~~~~~~~~ - interface Record { [key: string]: any; } - interface RecordMap { [dataID: string]: Record | null | undefined; } + interface Record { + [key: string]: any; + } + interface RecordMap { + [dataID: string]: Record | null | undefined; + } // ~~~~~~~~~~~~~~~~~~~~~ // Network @@ -772,7 +741,10 @@ export namespace RelayRuntimeTypes { * Creates an implementation of the `Network` interface defined in * `RelayNetworkTypes` given `fetch` and `subscribe` functions. */ - static create(fetchFn: typeof RelayCommonTypes.FetchFunction, subscribeFn?: RelayCommonTypes.SubscribeFunction): RelayNetwork; + static create( + fetchFn: typeof RelayCommonTypes.FetchFunction, + subscribeFn?: RelayCommonTypes.SubscribeFunction + ): RelayNetwork; } // ~~~~~~~~~~~~~~~~~~~~~ @@ -784,12 +756,9 @@ export namespace RelayRuntimeTypes { delete(dataID: RelayCommonTypes.DataID): void; get(dataID: RelayCommonTypes.DataID): Record | void; getRecordIDs(): RelayCommonTypes.DataID[]; - getStatus(dataID: RelayCommonTypes.DataID): 'EXISTENT' | 'NONEXISTENT' | 'UNKNOWN'; + getStatus(dataID: RelayCommonTypes.DataID): "EXISTENT" | "NONEXISTENT" | "UNKNOWN"; has(dataID: RelayCommonTypes.DataID): boolean; - load( - dataID: RelayCommonTypes.DataID, - callback: (error: Error | null, record: Record | null) => void, - ): void; + load(dataID: RelayCommonTypes.DataID, callback: (error: Error | null, record: Record | null) => void): void; remove(dataID: RelayCommonTypes.DataID): void; set(dataID: RelayCommonTypes.DataID, record: Record): void; size(): number; @@ -807,10 +776,7 @@ export namespace RelayRuntimeTypes { lookup(selector: Selector): Snapshot; notify(): void; publish(source: RecordSource): void; - subscribe( - snapshot: Snapshot, - callback: (snapshot: Snapshot) => void, - ): RelayCommonTypes.Disposable; + subscribe(snapshot: Snapshot, callback: (snapshot: Snapshot) => void): RelayCommonTypes.Disposable; } // ~~~~~~~~~~~~~~~~~~~~~ @@ -955,7 +921,9 @@ export namespace RelayRuntimeTypes { * legacy Relay observer and directly return an Observable instead. */ static fromLegacy( - callback: (legacyObserver: RelayCommonTypes.LegacyObserver) => RelayCommonTypes.Disposable | RelayObservable, + callback: ( + legacyObserver: RelayCommonTypes.LegacyObserver + ) => RelayCommonTypes.Disposable | RelayObservable ): RelayObservable; /** @@ -1036,10 +1004,7 @@ export namespace RelayRuntimeTypes { // commitLocalUpdate // ~~~~~~~~~~~~~~~~~~~~~ // exposed through RelayModern, not Runtime directly - type commitLocalUpdate = ( - environment: Environment, - updater: RelayCommonTypes.StoreUpdater, - ) => void; + type commitLocalUpdate = (environment: Environment, updater: RelayCommonTypes.StoreUpdater) => void; // ~~~~~~~~~~~~~~~~~~~~~ // commitRelayModernMutation @@ -1058,7 +1023,7 @@ export namespace RelayRuntimeTypes { } function commitRelayModernMutation( environment: Environment, - config: MutationConfig, + config: MutationConfig ): RelayCommonTypes.Disposable; // ~~~~~~~~~~~~~~~~~~~~~ @@ -1094,7 +1059,7 @@ export namespace RelayRuntimeTypes { environment: any, // FIXME - $FlowFixMe in facebook source code taggedNode: RelayCommonTypes.GraphQLTaggedNode, variables: RelayCommonTypes.Variables, - cacheConfig?: RelayCommonTypes.CacheConfig, + cacheConfig?: RelayCommonTypes.CacheConfig ): Promise; // FIXME - $FlowFixMe in facebook source code // ~~~~~~~~~~~~~~~~~~~~~ @@ -1112,7 +1077,7 @@ export namespace RelayRuntimeTypes { } function requestRelaySubscription( environment: Environment, - config: GraphQLSubscriptionConfig, + config: GraphQLSubscriptionConfig ): RelayCommonTypes.Disposable; } diff --git a/types/relay-runtime/relay-runtime-tests.tsx b/types/relay-runtime/relay-runtime-tests.tsx index c6dd9c15a2..f786e4d5fa 100644 --- a/types/relay-runtime/relay-runtime-tests.tsx +++ b/types/relay-runtime/relay-runtime-tests.tsx @@ -1,11 +1,4 @@ -import { - Environment, - Network, - RecordSource, - Store, - ConnectionHandler, - ViewerHandler, -} from 'relay-runtime'; +import { Environment, Network, RecordSource, Store, ConnectionHandler, ViewerHandler } from "relay-runtime"; const source = new RecordSource(); const store = new Store(source); @@ -15,13 +8,9 @@ const store = new Store(source); // ~~~~~~~~~~~~~~~~~~~~~ // Define a function that fetches the results of an operation (query/mutation/etc) // and returns its results as a Promise: -function fetchQuery( - operation: any, - variables: { [key: string]: string }, - cacheConfig: {}, -) { - return fetch('/graphql', { - method: 'POST', +function fetchQuery(operation: any, variables: { [key: string]: string }, cacheConfig: {}) { + return fetch("/graphql", { + method: "POST", body: JSON.stringify({ query: operation.text, // GraphQL text from input variables, @@ -50,10 +39,10 @@ const environment = new Environment({ function handlerProvider(handle: any) { switch (handle) { // Augment (or remove from) this list: - case 'connection': return ConnectionHandler; - case 'viewer': return ViewerHandler; + case "connection": + return ConnectionHandler; + case "viewer": + return ViewerHandler; } - throw new Error( - `handlerProvider: No handler provided for ${handle}` - ); + throw new Error(`handlerProvider: No handler provided for ${handle}`); } From bafb5407cb8d37c6c8d34af91a0e546545726dd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 11 Oct 2017 15:56:18 +0200 Subject: [PATCH 3/7] [Relay] Fix dtslint issues with test files. --- types/react-relay/{ => test}/react-relay-classic-tests.tsx | 0 types/react-relay/{ => test}/react-relay-tests.tsx | 0 types/react-relay/tsconfig.json | 6 +++--- 3 files changed, 3 insertions(+), 3 deletions(-) rename types/react-relay/{ => test}/react-relay-classic-tests.tsx (100%) rename types/react-relay/{ => test}/react-relay-tests.tsx (100%) diff --git a/types/react-relay/react-relay-classic-tests.tsx b/types/react-relay/test/react-relay-classic-tests.tsx similarity index 100% rename from types/react-relay/react-relay-classic-tests.tsx rename to types/react-relay/test/react-relay-classic-tests.tsx diff --git a/types/react-relay/react-relay-tests.tsx b/types/react-relay/test/react-relay-tests.tsx similarity index 100% rename from types/react-relay/react-relay-tests.tsx rename to types/react-relay/test/react-relay-tests.tsx diff --git a/types/react-relay/tsconfig.json b/types/react-relay/tsconfig.json index 5447ff74ca..2b992f91c8 100644 --- a/types/react-relay/tsconfig.json +++ b/types/react-relay/tsconfig.json @@ -19,10 +19,10 @@ }, "files": [ "index.d.ts", - "react-relay-tests.tsx", - "react-relay-classic-tests.tsx", "classic.d.ts", "modern.d.ts", - "compat.d.ts" + "compat.d.ts", + "test/react-relay-tests.tsx", + "test/react-relay-classic-tests.tsx" ] } From 339eadd3e10e9f6b40461c573cc2e32572ed863e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 11 Oct 2017 15:56:44 +0200 Subject: [PATCH 4/7] [Relay] Fix namespace reference. --- types/relay-runtime/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/relay-runtime/index.d.ts b/types/relay-runtime/index.d.ts index 88abec0a9b..5b1554e929 100644 --- a/types/relay-runtime/index.d.ts +++ b/types/relay-runtime/index.d.ts @@ -90,7 +90,7 @@ export namespace RelayCommonTypes { variables: Variables, cacheConfig: CacheConfig, uploadables?: UploadableMap - ): Runtime.ObservableFromValue; + ): RelayRuntimeTypes.ObservableFromValue; /** * A function that executes a GraphQL subscription operation, returning one or @@ -104,7 +104,7 @@ export namespace RelayCommonTypes { variables: Variables, cacheConfig: CacheConfig, observer: LegacyObserver - ) => Runtime.RelayObservable | Disposable; + ) => RelayRuntimeTypes.RelayObservable | Disposable; // ~~~~~~~~~~~~~~~~~~~~~ // RelayStoreTypes From 3439a2d7a179616f834cc5bcf6d377a7f998358d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 11 Oct 2017 15:59:12 +0200 Subject: [PATCH 5/7] [Relay] Add myself to list of maintainers. --- types/react-relay/index.d.ts | 4 +++- types/relay-runtime/index.d.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/types/react-relay/index.d.ts b/types/react-relay/index.d.ts index 30cb29b3e3..cdb38afae6 100644 --- a/types/react-relay/index.d.ts +++ b/types/react-relay/index.d.ts @@ -1,6 +1,8 @@ // Type definitions for react-relay 1.3 // Project: https://github.com/facebook/relay -// Definitions by: Johannes Schickling , Matt Martin +// Definitions by: Johannes Schickling +// Matt Martin +// Eloy Durán // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.4 diff --git a/types/relay-runtime/index.d.ts b/types/relay-runtime/index.d.ts index 5b1554e929..a4867b4091 100644 --- a/types/relay-runtime/index.d.ts +++ b/types/relay-runtime/index.d.ts @@ -1,6 +1,7 @@ // Type definitions for relay-runtime 1.3 // Project: https://github.com/facebook/relay // Definitions by: Matt Martin +// Eloy Durán // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.4 From 091c46291e8635c31ed0e26ac24accd1d9697e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 11 Oct 2017 16:23:14 +0200 Subject: [PATCH 6/7] [Relay] Add generics for `getConnectionFromProps`. --- types/react-relay/modern.d.ts | 6 +++--- types/react-relay/test/react-relay-tests.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/types/react-relay/modern.d.ts b/types/react-relay/modern.d.ts index 13b43bf449..d4c422b823 100644 --- a/types/react-relay/modern.d.ts +++ b/types/react-relay/modern.d.ts @@ -105,9 +105,9 @@ export function FragmentVariablesGetter( prevVars: RelayCommonTypes.Variables, totalCount: number ): RelayCommonTypes.Variables; -export interface ConnectionConfig { +export interface ConnectionConfig { direction?: "backward" | "forward"; - getConnectionFromProps?(props: object): ConnectionData | undefined | null; + getConnectionFromProps?(props: T): ConnectionData | undefined | null; getFragmentVariables?: typeof FragmentVariablesGetter; getVariables( props: { [propName: string]: any }, @@ -119,7 +119,7 @@ export interface ConnectionConfig { export function createPaginationContainer( Component: ReactBaseComponent, fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap, - connectionConfig: ConnectionConfig + connectionConfig: ConnectionConfig ): ReactBaseComponent; // ~~~~~~~~~~~~~~~~~~~~~ diff --git a/types/react-relay/test/react-relay-tests.tsx b/types/react-relay/test/react-relay-tests.tsx index 97cc5d47d9..c7d144122b 100644 --- a/types/react-relay/test/react-relay-tests.tsx +++ b/types/react-relay/test/react-relay-tests.tsx @@ -182,7 +182,7 @@ const FeedPaginationContainer = createPaginationContainer( }, { direction: "forward", - getConnectionFromProps(props: { user: { feed: any } }) { + getConnectionFromProps(props) { return props.user && props.user.feed; }, getFragmentVariables(prevVars, totalCount) { From 08f193a6941ad3b3fbf701a63f0425930e6f9e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Thu, 12 Oct 2017 00:46:10 +0200 Subject: [PATCH 7/7] [Relay] Return `null` instead of `void` for Flow Maybe types. --- types/react-relay/test/react-relay-tests.tsx | 6 ++++ types/relay-runtime/index.d.ts | 30 ++++++++++---------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/types/react-relay/test/react-relay-tests.tsx b/types/react-relay/test/react-relay-tests.tsx index c7d144122b..80380122f7 100644 --- a/types/react-relay/test/react-relay-tests.tsx +++ b/types/react-relay/test/react-relay-tests.tsx @@ -279,6 +279,12 @@ function markNotificationAsRead(source: string, storyID: string) { 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"); + } + } }); } diff --git a/types/relay-runtime/index.d.ts b/types/relay-runtime/index.d.ts index a4867b4091..69f5088ab4 100644 --- a/types/relay-runtime/index.d.ts +++ b/types/relay-runtime/index.d.ts @@ -137,17 +137,17 @@ export namespace RelayCommonTypes { interface RecordSourceSelectorProxy { create(dataID: DataID, typeName: string): RecordProxy; delete(dataID: DataID): void; - get(dataID: DataID): RecordProxy | void; + get(dataID: DataID): RecordProxy | null; getRoot(): RecordProxy; - getRootField(fieldName: string): RecordProxy | void; - getPluralRootField(fieldName: string): RecordProxy[] | void; + getRootField(fieldName: string): RecordProxy | null; + getPluralRootField(fieldName: string): RecordProxy[] | null; } interface RecordProxy { copyFieldsFrom(source: RecordProxy): void; getDataID(): DataID; - getLinkedRecord(name: string, args?: Variables): RecordProxy | void; - getLinkedRecords(name: string, args?: Variables): Array | void; + getLinkedRecord(name: string, args?: Variables): RecordProxy | null; + getLinkedRecords(name: string, args?: Variables): Array | null; getOrCreateLinkedRecord(name: string, typeName: string, args?: Variables): RecordProxy; getType(): string; getValue(name: string, args?: Variables): any; @@ -163,7 +163,7 @@ export namespace RelayCommonTypes { interface RecordSourceProxy { create(dataID: DataID, typeName: string): RecordProxy; delete(dataID: DataID): void; - get(dataID: DataID): Array | void; + get(dataID: DataID): Array | null; getRoot(): RecordProxy; } @@ -457,7 +457,7 @@ export namespace RelayCommonTypes { * const childData = environment.lookup(childSelector).data; * ``` */ - getSelector(operationVariables: Variables, fragment: TFragment, prop: any): CSelector | void; + getSelector(operationVariables: Variables, fragment: TFragment, prop: any): CSelector | null; /** * Given the result `items` from a parent that fetched `fragment`, creates a @@ -469,7 +469,7 @@ export namespace RelayCommonTypes { operationVariables: Variables, fragment: TFragment, props: any[] - ): Array> | void; + ): Array> | null; /** * Given a mapping of keys -> results and a mapping of keys -> fragments, @@ -590,8 +590,8 @@ export namespace RelayCommonTypes { } ) => void; interface NetworkLayer { - sendMutation(request: RelayMutationRequest): Promise | void; - sendQueries(requests: RelayQueryRequest[]): Promise | void; + sendMutation(request: RelayMutationRequest): Promise | null; + sendQueries(requests: RelayQueryRequest[]): Promise | null; supports(...options: string[]): boolean; } interface QueryResult { @@ -681,7 +681,7 @@ export namespace RelayRuntimeTypes { // ~~~~~~~~~~~~~~~~~~~~~ // RelayDefaultHandlerProvider // ~~~~~~~~~~~~~~~~~~~~~ - function HandlerProvider(name: string): typeof RelayCommonTypes.Handler | void; + function HandlerProvider(name: string): typeof RelayCommonTypes.Handler | null; // ~~~~~~~~~~~~~~~~~~~~~ // RelayModernEnvironment @@ -755,7 +755,7 @@ export namespace RelayRuntimeTypes { constructor(records?: RecordMap); clear(): void; delete(dataID: RelayCommonTypes.DataID): void; - get(dataID: RelayCommonTypes.DataID): Record | void; + get(dataID: RelayCommonTypes.DataID): Record | null; getRecordIDs(): RelayCommonTypes.DataID[]; getStatus(dataID: RelayCommonTypes.DataID): "EXISTENT" | "NONEXISTENT" | "UNKNOWN"; has(dataID: RelayCommonTypes.DataID): boolean; @@ -833,14 +833,14 @@ export namespace RelayRuntimeTypes { * value is another Record instead of a scalar). May throw if the field is * present but not a scalar linked record. */ - getLinkedRecord(name: string, args?: RelayCommonTypes.Variables): RecordInspector | void; + getLinkedRecord(name: string, args?: RelayCommonTypes.Variables): RecordInspector | null; /** * Returns an array of inspectors for the given plural "linked" field (a field * whose value is an array of Records instead of a scalar). May throw if the * field is present but not a plural linked record. */ - getLinkedRecords(name: string, args?: RelayCommonTypes.Variables): RecordInspector[] | void; + getLinkedRecords(name: string, args?: RelayCommonTypes.Variables): RecordInspector[] | null; } class RelayRecordSourceInspector { @@ -850,7 +850,7 @@ export namespace RelayRuntimeTypes { * Returns an inspector for the record with the given id, or null/undefined if * that record is deleted/unfetched. */ - get(dataID: RelayCommonTypes.DataID): RecordInspector | void; + get(dataID: RelayCommonTypes.DataID): RecordInspector | null; /** * Returns a list of ": " for each record in the store that has an * `id`.