diff --git a/types/graphql-react/graphql-react-tests.tsx b/types/graphql-react/graphql-react-tests.tsx
new file mode 100644
index 0000000000..a1c80d7995
--- /dev/null
+++ b/types/graphql-react/graphql-react-tests.tsx
@@ -0,0 +1,47 @@
+import React from "react";
+import { GraphQL, GraphQLContext, useGraphQL } from "graphql-react";
+
+const graphql = new GraphQL();
+
+function App() {
+ const { loading, cacheValue } = useGraphQL<
+ {node: null | {id: string}},
+ {id: string}
+ >({
+ fetchOptionsOverride(options) {
+ options.url = "/graphql";
+ },
+ operation: {
+ variables: {
+ id: "123456"
+ },
+ query: `
+ query($id: !String) {
+ node(id: $id) {
+ id
+ }
+ }
+ `
+ }
+ });
+
+ if (loading) {
+ return
Loading...
;
+ }
+
+ return (
+ {
+ cacheValue && cacheValue.data && cacheValue.data.node
+ ? "exists"
+ : "does not exist"
+ }
+ );
+}
+
+function Root() {
+ return (
+
+
+
+ );
+}
diff --git a/types/graphql-react/index.d.ts b/types/graphql-react/index.d.ts
new file mode 100644
index 0000000000..9ee919bd16
--- /dev/null
+++ b/types/graphql-react/index.d.ts
@@ -0,0 +1,139 @@
+// Type definitions for graphql-react 8.1
+// Project: https://github.com/jaydenseric/graphql-react#readme
+// Definitions by: Mike Marcacci
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+// TypeScript Version: 3.3
+
+// The no-unnecessary-generics rule is stupid and overrestrictive. It is a
+// perfectly valid and often useful to type-constrain a wrapping object.
+/* tslint:disable:no-unnecessary-generics */
+
+import { ReactNode, Context } from "react";
+
+export const GraphQLContext: Context;
+
+export interface HttpError {
+ status: number;
+ statusText: string;
+}
+
+export type GraphQLCacheKey = string;
+export interface GraphQLCacheValue {
+ fetchError: null | string;
+ httpError: null | HttpError;
+ parseError: null | string;
+ graphQLErrors:
+ | null
+ | Array<{
+ message: string;
+ path: string[];
+ locations: Array<{ column: number; line: number }>;
+ }>;
+ data: T;
+}
+
+export interface GraphQLCache {
+ [key: string]: GraphQLCacheValue;
+}
+
+export interface GraphQLFetchOptions {
+ url: string;
+ body: string | FormData;
+ headers: Headers;
+ credentials: null | string;
+}
+
+export type GraphQLFetchOptionsOverride = (
+ options: GraphQLFetchOptions
+) => void;
+
+export type GraphQLOperation = {
+ query: string;
+} & (V extends undefined ? {} : { variables: V });
+
+export interface GraphQLOperationLoading {
+ cacheKey: GraphQLCacheKey;
+ cacheValue: undefined | GraphQLCacheValue;
+ cacheValuePromise: Promise>;
+}
+
+export interface GraphQLOperationStatus {
+ load: () => void;
+ loading: boolean;
+ cacheKey: GraphQLCacheKey;
+ cacheValue?: GraphQLCacheValue;
+}
+
+export class GraphQL {
+ constructor(options?: { cache?: GraphQLCache });
+
+ on(
+ type: "reset",
+ handler: (event: { exceptCacheKey: GraphQLCacheKey }) => void
+ ): void;
+
+ on(
+ type: "cache",
+ handler: (event: {
+ cacheKey: GraphQLCacheKey;
+ cacheValue: GraphQLCacheValue;
+ }) => void
+ ): void;
+
+ on(
+ type: "fetch",
+ handler: (event: {
+ cacheKey: GraphQLCacheKey;
+ cacheValuePromise: Promise>;
+ }) => void
+ ): void;
+
+ off(
+ type: "reset",
+ handler: (event: { exceptCacheKey: GraphQLCacheKey }) => void
+ ): void;
+
+ off(
+ type: "cache",
+ handler: (event: {
+ cacheKey: GraphQLCacheKey;
+ cacheValue: GraphQLCacheValue;
+ }) => void
+ ): void;
+
+ off(
+ type: "fetch",
+ handler: (event: {
+ cacheKey: GraphQLCacheKey;
+ cacheValuePromise: Promise>;
+ }) => void
+ ): void;
+
+ reset(exceptCacheKey?: string): void;
+ operate(options: {
+ operation: GraphQLOperation;
+ fetchOptionsOverride?: GraphQLFetchOptionsOverride;
+ reloadOnLoad?: boolean;
+ resetOnLoad?: boolean;
+ }): GraphQLOperationLoading;
+
+ cache: GraphQLCache;
+}
+
+export function reportCacheErrors(event: any): void;
+
+export function ssr(
+ grapphql: GraphQL,
+ node: ReactNode,
+ render?: (element: ReactNode) => string
+): void;
+
+export function useGraphQL(options: {
+ fetchOptionsOverride?: GraphQLFetchOptionsOverride;
+ loadOnMount?: boolean;
+ loadOnReload?: boolean;
+ loadOnReset?: boolean;
+ reloadOnLoad?: boolean;
+ resetOnLoad?: boolean;
+ operation: GraphQLOperation;
+}): GraphQLOperationStatus;
diff --git a/types/graphql-react/tsconfig.json b/types/graphql-react/tsconfig.json
new file mode 100644
index 0000000000..16a784d5cc
--- /dev/null
+++ b/types/graphql-react/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "lib": [
+ "es6",
+ "dom"
+ ],
+ "noImplicitAny": true,
+ "noImplicitThis": true,
+ "strictNullChecks": true,
+ "strictFunctionTypes": true,
+ "baseUrl": "../",
+ "typeRoots": [
+ "../"
+ ],
+ "types": [],
+ "noEmit": true,
+ "forceConsistentCasingInFileNames": true,
+ "jsx": "react",
+ "esModuleInterop": true
+ },
+ "files": [
+ "index.d.ts",
+ "graphql-react-tests.tsx"
+ ]
+}
diff --git a/types/graphql-react/tslint.json b/types/graphql-react/tslint.json
new file mode 100644
index 0000000000..3db14f85ea
--- /dev/null
+++ b/types/graphql-react/tslint.json
@@ -0,0 +1 @@
+{ "extends": "dtslint/dt.json" }