diff --git a/types/react-relay/index.d.ts b/types/react-relay/index.d.ts index 2e41dcbd6a..acce5bf832 100644 --- a/types/react-relay/index.d.ts +++ b/types/react-relay/index.d.ts @@ -7,7 +7,7 @@ // Cameron Knight // Kaare Hoff Skovgaard // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.8 +// TypeScript Version: 2.9 // Prettified with: // $ prettier --parser typescript --tab-width 4 --semi --trailing-comma es5 --write --print-width 120 \ @@ -88,24 +88,27 @@ export const graphql: GraphqlInterface; // ~~~~~~~~~~~~~~~~~~~~~ // ReactRelayQueryRenderer // ~~~~~~~~~~~~~~~~~~~~~ -export interface QueryRendererProps { + +export interface QueryRendererProps { cacheConfig?: RelayRuntimeTypes.CacheConfig; environment: RelayRuntimeTypes.Environment; query?: RelayRuntimeTypes.GraphQLTaggedNode | null; - render(readyState: ReadyState): React.ReactElement | undefined | null; - variables: RelayRuntimeTypes.Variables; + render(readyState: ReadyState): React.ReactElement | undefined | null; + variables: T["variables"]; rerunParamExperimental?: RelayRuntimeTypes.RerunParam; } -export interface ReadyState { +export interface ReadyState { error: Error | undefined | null; - props: { [propName: string]: any } | undefined | null; + props: T | undefined | null; retry?(): void; } -export interface QueryRendererState { - readyState: ReadyState; -} -export class ReactRelayQueryRenderer extends React.Component {} -export class QueryRenderer extends ReactRelayQueryRenderer {} + +export class ReactRelayQueryRenderer extends React.Component< + QueryRendererProps +> {} +export class QueryRenderer< + T extends RelayRuntimeTypes.OperationBase = RelayRuntimeTypes.OperationDefaults +> extends ReactRelayQueryRenderer {} // ~~~~~~~~~~~~~~~~~~~~~ // createFragmentContainer diff --git a/types/react-relay/test/react-relay-tests.tsx b/types/react-relay/test/react-relay-tests.tsx index 9d08ed42d6..f19d2a818c 100644 --- a/types/react-relay/test/react-relay-tests.tsx +++ b/types/react-relay/test/react-relay-tests.tsx @@ -1,3 +1,5 @@ +// tslint:disable:interface-over-type-literal + import * as React from "react"; import { Environment, Network, RecordSource, Store, ConnectionHandler, FragmentReference } from "relay-runtime"; @@ -28,8 +30,21 @@ const modernEnvironment = new Environment({ network, store }); // ~~~~~~~~~~~~~~~~~~~~~ // Modern QueryRenderer // ~~~~~~~~~~~~~~~~~~~~~ + +// Artifact produced by relay-compiler-language-typescript +type MyQueryRendererVariables = { + pageID: string; +}; +type MyQueryRendererResponse = { + name: string; +}; +type MyQueryRenderer = { + variables: MyQueryRendererVariables; + response: MyQueryRendererResponse; +}; + const MyQueryRenderer = (props: { name: string; show: boolean }) => ( - environment={modernEnvironment} query={ props.show @@ -82,7 +97,6 @@ type StoryLike = (storyID: string) => void; // Artifact produced by relay-compiler-language-typescript declare const _Story_story$ref: unique symbol; type Story_story$ref = typeof _Story_story$ref; -// tslint:disable-next-line:interface-over-type-literal type Story_story = { readonly id: string; readonly text: string; @@ -173,7 +187,6 @@ declare const _FeedStories_feed$ref: unique symbol; type FeedStories_feed$ref = typeof _FeedStories_feed$ref; declare const _FeedStory_edges$ref: unique symbol; type FeedStory_edges$ref = typeof _FeedStory_edges$ref; -// tslint:disable-next-line:interface-over-type-literal type FeedStories_feed = { readonly edges: ReadonlyArray<{ readonly node: { @@ -184,7 +197,6 @@ type FeedStories_feed = { }>; readonly " $refType": FeedStories_feed$ref; }; -// tslint:disable-next-line:interface-over-type-literal type FeedStory_edges = ReadonlyArray<{ readonly publishedAt: string; readonly " $refType": FeedStory_edges$ref; @@ -255,7 +267,6 @@ const Feed = (() => { // Artifact produced by relay-compiler-language-typescript declare const _UserFeed_user$ref: unique symbol; type UserFeed_user$ref = typeof _UserFeed_user$ref; -// tslint:disable-next-line:interface-over-type-literal type UserFeed_user = { readonly feed: { readonly pageInfo: { @@ -372,7 +383,7 @@ export const mutation = graphql` export const optimisticResponse = { markReadNotification: { notification: { - seenState: "SEEN", + seenState: "SEEN" as "SEEN", }, }, }; @@ -408,26 +419,47 @@ export const configs = [ ]; function markNotificationAsRead(source: string, storyID: string) { - const variables = { - input: { - source, - storyID, - }, + // Artifact produced by relay-compiler-language-typescript + type MyMutationVariables = { + readonly input: { + readonly source: string; + readonly storyID: string; + }; + }; + type MyMutationResponse = { + readonly markReadNotification: { + readonly notification: { + readonly seenState: "SEEN" | "UNSEEN"; + }; + }; + }; + type MyMutation = { + readonly variables: MyMutationVariables; + readonly response: MyMutationResponse; }; - commitMutation(modernEnvironment, { + commitMutation(modernEnvironment, { configs, mutation, optimisticResponse, - variables, + variables: { + input: { + source, + storyID, + }, + }, onCompleted: (response, errors) => { - console.log("Response received from server."); + if (errors) { + console.log(`Errors received from server: ${errors.map(error => error.message).join(", ")}`); + } else { + console.log(`Response received from server: ${response.markReadNotification.notification.seenState}`); + } }, onError: err => console.error(err), updater: (store, data) => { - const field = store.get(storyID); - if (field) { - field.setValue(data.story, "story"); + const story = store.get(storyID); + if (story) { + story.setValue(data.markReadNotification.notification.seenState, "seenState"); } }, }); diff --git a/types/relay-runtime/index.d.ts b/types/relay-runtime/index.d.ts index acfec9eaa5..42cd633b57 100644 --- a/types/relay-runtime/index.d.ts +++ b/types/relay-runtime/index.d.ts @@ -3,7 +3,7 @@ // Definitions by: Matt Martin // Eloy DurĂ¡n // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.4 +// TypeScript Version: 2.9 // Prettified with: // $ prettier --parser typescript --tab-width 4 --semi --trailing-comma es5 --write --print-width 120 \ @@ -51,6 +51,15 @@ export type RequestNode = ConcreteRequest | ConcreteBatchRequest; // tslint:disable-next-line:no-const-enum export const enum FragmentReference {} +export interface OperationBase { + variables: object; + response: object; +} +export interface OperationDefaults { + variables: Variables; + response: Variables; +} + // ~~~~~~~~~~~~~~~~~~~~~ // RelayQL // ~~~~~~~~~~~~~~~~~~~~~ @@ -140,11 +149,11 @@ export type StoreUpdater = (store: RecordSourceProxy) => void; * order to easily access the root fields of a query/mutation as well as a * second argument of the response object of the mutation. */ -export type SelectorStoreUpdater = ( +export type SelectorStoreUpdater = ( store: RecordSourceSelectorProxy, // Actually RelayCombinedEnvironmentTypes#SelectorData, but mixed is // inconvenient to access deeply in product code. - data: any // FLOW FIXME + data: T ) => void; /** @@ -483,7 +492,9 @@ export interface CUnstableEnvironmentCore, props: Props - ): { [key: string]: CSelector | Array> | null | undefined }; + ): { + [key: string]: CSelector | Array> | null | undefined; + }; /** * Given a mapping of keys -> results and a mapping of keys -> fragments, @@ -1005,18 +1016,22 @@ export type commitLocalUpdate = (environment: Environment, updater: StoreUpdater // commitRelayModernMutation // ~~~~~~~~~~~~~~~~~~~~~ // exposed through RelayModern, not Runtime directly -export interface MutationConfig { +export interface MutationConfig { configs?: RelayMutationConfig[]; mutation: GraphQLTaggedNode; - variables: Variables; + variables: T["variables"]; uploadables?: UploadableMap; - onCompleted?(response: T, errors: PayloadError[] | null | undefined): void; + onCompleted?(response: T["response"], errors: PayloadError[] | null | undefined): void; onError?(error?: Error): void; - optimisticUpdater?: SelectorStoreUpdater; - optimisticResponse?: object; - updater?: SelectorStoreUpdater; + optimisticUpdater?: SelectorStoreUpdater; + optimisticResponse?: T["response"]; + updater?: SelectorStoreUpdater; } -export function commitRelayModernMutation(environment: Environment, config: MutationConfig): Disposable; +export function commitRelayModernMutation( + environment: Environment, + // tslint:disable-next-line:no-unnecessary-generics + config: MutationConfig +): Disposable; // ~~~~~~~~~~~~~~~~~~~~~ // applyRelayModernOptimisticMutation