Skip to content

Commit

Permalink
TypeScript definitions for recoil-relay (#1801)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #1801

Add initial TypeScript definitions for `recoil-relay` package.

Note that the Relay TypeScript definitions are MUCH more lenient than their Flow counterparts.  The `GraphQLTaggedNode` type used for the GraphQL string is not parameterized at all, so we cannot check that the variables and response types actually match the expected type.

This requires upgrading to TypeScript 3.9 due to some Relay dependencies.

Reviewed By: mondaychen

Differential Revision: D36468606

fbshipit-source-id: c9574aa540c0b2d78a26b384cbccf758b5e37078
  • Loading branch information
drarmstr authored and facebook-github-bot committed May 31, 2022
1 parent 3ee7dce commit 530ef77
Show file tree
Hide file tree
Showing 11 changed files with 432 additions and 19 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@
"@rollup/plugin-commonjs": "^11.1.0",
"@rollup/plugin-node-resolve": "^7.1.3",
"@rollup/plugin-replace": "^2.3.2",
"@types/react": ">=16.13.1",
"@types/react": ">=18.0.9",
"@types/react-relay": ">=13.0.2",
"@types/relay-runtime": ">=13.0.3",
"babel-jest": "^26.0.1",
"babel-plugin-module-resolver": "^4.0.0",
"babel-plugin-relay": "^13.2.0",
Expand Down
2 changes: 1 addition & 1 deletion typescript/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Minimum TypeScript Version: 3.7
// Minimum TypeScript Version: 3.9

/**
* Copyright (c) Facebook, Inc. and its affiliates.
Expand Down
260 changes: 260 additions & 0 deletions typescript/recoil-relay-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
// Minimum TypeScript Version: 3.9

/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails oncall+recoil
*/

import React = require('react');
import { atom } from 'recoil';
import {
EnvironmentKey,
RecoilRelayEnvironment,
RecoilRelayEnvironmentProvider,
graphQLQueryEffect,
graphQLSubscriptionEffect,
graphQLMutationEffect,
graphQLSelector,
graphQLSelectorFamily,
} from 'recoil-relay';
import { IEnvironment, graphql } from 'relay-runtime';
import { useRelayEnvironment } from 'react-relay';

// Environment
const myEnv: IEnvironment = useRelayEnvironment();

// EnvironmentKey
const myEnvKey: EnvironmentKey = new EnvironmentKey('test');

// <RecoilRelayEnvironment>
RecoilRelayEnvironment({ // $ExpectType ReactElement<any, any> | null
children: React.createElement('div'),
environment: myEnv,
environmentKey: myEnvKey,
});
RecoilRelayEnvironment({ // $ExpectType ReactElement<any, any> | null
children: React.createElement('div'),
environment: myEnv,
environmentKey: myEnvKey,
extraArg: 'ERROR', // $ExpectError
});
RecoilRelayEnvironment({ // $ExpectError
children: React.createElement('div'),
environment: myEnv,
});

// <RecoilRelayEnvironmentProvider>
RecoilRelayEnvironmentProvider({ // $ExpectType ReactElement<any, any> | null
children: React.createElement('div'),
environment: myEnv,
environmentKey: myEnvKey,
});
RecoilRelayEnvironmentProvider({ // $ExpectType ReactElement<any, any> | null
children: React.createElement('div'),
environment: myEnv,
environmentKey: myEnvKey,
extraArg: 'ERROR', // $ExpectError
});
RecoilRelayEnvironmentProvider({ // $ExpectError
children: React.createElement('div'),
environment: myEnv,
});

// graphQLQueryEffect()
atom<string>({
key: 'key',
effects: [graphQLQueryEffect({
environment: myEnv,
query: graphql`query...`,
variables: {foo: 'bar'},
mapResponse: (data: {str: string}) => data.str,
})],
});
atom<string>({
key: 'key',
effects: [graphQLQueryEffect({
environment: myEnvKey,
query: graphql`query...`,
variables: null,
mapResponse: (data: {str: string}) => data.str,
})],
});
atom<string>({
key: 'key',
effects: [graphQLQueryEffect({ // $ExpectError
environment: myEnv,
query: graphql`query...`,
variables: {foo: 'bar'},
mapResponse: (data: {str: string}) => data,
})],
});

// graphQLSubscriptionEffect()
atom<string>({
key: 'key',
effects: [graphQLSubscriptionEffect({
environment: myEnv,
subscription: graphql`subscription...`,
variables: {foo: 'bar'},
mapResponse: (data: {str: string}) => data.str,
})],
});
atom<string>({
key: 'key',
effects: [graphQLSubscriptionEffect({
environment: myEnvKey,
subscription: graphql`subscription...`,
variables: null,
mapResponse: (data: {str: string}) => data.str,
})],
});
atom<string>({
key: 'key',
effects: [graphQLSubscriptionEffect({ // $ExpectError
environment: myEnv,
subscription: graphql`subscription...`,
variables: {foo: 'bar'},
mapResponse: (data: {str: string}) => data,
})],
});

// graphQLMutationEffect()
atom<string>({
key: 'key',
effects: [graphQLMutationEffect({
environment: myEnv,
mutation: graphql`mutation...`,
variables: str => ({foo: str}),
})],
});
atom<string>({
key: 'key',
effects: [graphQLMutationEffect({
environment: myEnvKey,
mutation: graphql`mutation...`,
variables: () => null,
})],
});
atom<string>({
key: 'key',
effects: [graphQLMutationEffect<string, {bar: string}>({
environment: myEnv,
mutation: graphql`mutation...`,
variables: str => ({foo: str}),
updater_UNSTABLE: (store, data) => {
store; // $ExpectType RecordSourceSelectorProxy<{ bar: string; }>
data; // $ExpectType { bar: string; }
},
optimisticUpdater_UNSTABLE: (store, data) => {
store; // $ExpectType RecordSourceSelectorProxy<{ bar: string; }>
data; // $ExpectType { bar: string; }
},
optimisticResponse_UNSTABLE: str => ({bar: str}),
})],
});

// graphQLSelector()
graphQLSelector<{foo: string}, string>({ // $ExpectType RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
});
graphQLSelector<{foo: string}, string>({ // $ExpectType RecoilState<string>
key: 'key',
environment: myEnvKey,
query: graphql`query...`,
variables: ({get}) => {
get; // $ExpectType GetRecoilValue
return null;
},
mapResponse: data => data.str,
});
graphQLSelector<{foo: string}, string>({ // $ExpectType RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
mutations: {
mutation: graphql`mutation...`,
variables: (str: string) => ({eggs: str}),
},
});
graphQLSelector<{foo: string}, string>({ // $ExpectType RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
extraArg: 'ERROR', // $ExpectError
});
graphQLSelector<{foo: string}, string>({ // $ExpectError
key: 'key',
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
});
graphQLSelector<{foo: string}, string>({ // $ExpectType RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: 'ERROR', // $ExpectError
mapResponse: data => data.str,
});

// graphQLSelectorFamily()
graphQLSelectorFamily<{foo: string}, string, string>({ // $ExpectType (parameter: string) => RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
});
graphQLSelectorFamily<{foo: string}, string, string>({ // $ExpectType (parameter: string) => RecoilState<string>
key: 'key',
environment: myEnvKey,
query: graphql`query...`,
variables: (str: string) => ({get}) => {
get; // $ExpectType GetRecoilValue
return null;
},
mapResponse: data => data.str,
});
graphQLSelectorFamily<{foo: string}, string, string>({ // $ExpectType (parameter: string) => RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
mutations: {
mutation: graphql`mutation...`,
variables: (str: string) => (param: string) => ({eggs: str}),
},
});
graphQLSelectorFamily<{foo: string}, string, string>({ // $ExpectType (parameter: string) => RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
extraArg: 'ERROR', // $ExpectError
});
graphQLSelectorFamily<{foo: string}, string, string>({ // $ExpectError
key: 'key',
query: graphql`query...`,
variables: {foo: '123'},
mapResponse: data => data.str,
});
graphQLSelectorFamily<{foo: string}, string, string>({ // $ExpectType (parameter: string) => RecoilState<string>
key: 'key',
environment: myEnv,
query: graphql`query...`,
variables: 'ERROR', // $ExpectError
mapResponse: data => data.str,
});
Loading

0 comments on commit 530ef77

Please sign in to comment.