Skip to content

Commit 5e6a5b9

Browse files
authored
Covariant Wrapping Types (#1136)
**Semi-breaking: Those using flow should change from `new GraphQLList(t)` and `new GraphQLNonNull(t)` to `GraphQLList(t)` and `GraphQLNonNull(t)`** Because class constructors are contravariant since flow/js lacks a "finally" keyword, we need to use functions to represent covariance in GraphQLList and GraphQLNonNull. By having wrapping types be covariant, we can enable more checks and have more accurate predicates for refining types in GraphQL utilities.
1 parent 40f73fd commit 5e6a5b9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+475
-494
lines changed

src/__tests__/starWarsSchema.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,21 @@ const characterInterface = new GraphQLInterfaceType({
110110
description: 'A character in the Star Wars Trilogy',
111111
fields: () => ({
112112
id: {
113-
type: new GraphQLNonNull(GraphQLString),
113+
type: GraphQLNonNull(GraphQLString),
114114
description: 'The id of the character.',
115115
},
116116
name: {
117117
type: GraphQLString,
118118
description: 'The name of the character.',
119119
},
120120
friends: {
121-
type: new GraphQLList(characterInterface),
121+
type: GraphQLList(characterInterface),
122122
description:
123123
'The friends of the character, or an empty list if they ' +
124124
'have none.',
125125
},
126126
appearsIn: {
127-
type: new GraphQLList(episodeEnum),
127+
type: GraphQLList(episodeEnum),
128128
description: 'Which movies they appear in.',
129129
},
130130
secretBackstory: {
@@ -159,21 +159,21 @@ const humanType = new GraphQLObjectType({
159159
description: 'A humanoid creature in the Star Wars universe.',
160160
fields: () => ({
161161
id: {
162-
type: new GraphQLNonNull(GraphQLString),
162+
type: GraphQLNonNull(GraphQLString),
163163
description: 'The id of the human.',
164164
},
165165
name: {
166166
type: GraphQLString,
167167
description: 'The name of the human.',
168168
},
169169
friends: {
170-
type: new GraphQLList(characterInterface),
170+
type: GraphQLList(characterInterface),
171171
description:
172172
'The friends of the human, or an empty list if they have none.',
173173
resolve: human => getFriends(human),
174174
},
175175
appearsIn: {
176-
type: new GraphQLList(episodeEnum),
176+
type: GraphQLList(episodeEnum),
177177
description: 'Which movies they appear in.',
178178
},
179179
homePlanet: {
@@ -209,21 +209,21 @@ const droidType = new GraphQLObjectType({
209209
description: 'A mechanical creature in the Star Wars universe.',
210210
fields: () => ({
211211
id: {
212-
type: new GraphQLNonNull(GraphQLString),
212+
type: GraphQLNonNull(GraphQLString),
213213
description: 'The id of the droid.',
214214
},
215215
name: {
216216
type: GraphQLString,
217217
description: 'The name of the droid.',
218218
},
219219
friends: {
220-
type: new GraphQLList(characterInterface),
220+
type: GraphQLList(characterInterface),
221221
description:
222222
'The friends of the droid, or an empty list if they have none.',
223223
resolve: droid => getFriends(droid),
224224
},
225225
appearsIn: {
226-
type: new GraphQLList(episodeEnum),
226+
type: GraphQLList(episodeEnum),
227227
description: 'Which movies they appear in.',
228228
},
229229
secretBackstory: {
@@ -275,7 +275,7 @@ const queryType = new GraphQLObjectType({
275275
args: {
276276
id: {
277277
description: 'id of the human',
278-
type: new GraphQLNonNull(GraphQLString),
278+
type: GraphQLNonNull(GraphQLString),
279279
},
280280
},
281281
resolve: (root, { id }) => getHuman(id),
@@ -285,7 +285,7 @@ const queryType = new GraphQLObjectType({
285285
args: {
286286
id: {
287287
description: 'id of the droid',
288-
type: new GraphQLNonNull(GraphQLString),
288+
type: GraphQLNonNull(GraphQLString),
289289
},
290290
},
291291
resolve: (root, { id }) => getDroid(id),

src/execution/__tests__/abstract-promise-test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ describe('Execute: Handles execution of abstract types with promises', () => {
7272
name: 'Query',
7373
fields: {
7474
pets: {
75-
type: new GraphQLList(PetType),
75+
type: GraphQLList(PetType),
7676
resolve() {
7777
return [new Dog('Odie', true), new Cat('Garfield', false)];
7878
},
@@ -145,7 +145,7 @@ describe('Execute: Handles execution of abstract types with promises', () => {
145145
name: 'Query',
146146
fields: {
147147
pets: {
148-
type: new GraphQLList(PetType),
148+
type: GraphQLList(PetType),
149149
resolve() {
150150
return [new Dog('Odie', true), new Cat('Garfield', false)];
151151
},
@@ -217,7 +217,7 @@ describe('Execute: Handles execution of abstract types with promises', () => {
217217
name: 'Query',
218218
fields: {
219219
pets: {
220-
type: new GraphQLList(PetType),
220+
type: GraphQLList(PetType),
221221
resolve() {
222222
return [new Dog('Odie', true), new Cat('Garfield', false)];
223223
},
@@ -304,7 +304,7 @@ describe('Execute: Handles execution of abstract types with promises', () => {
304304
name: 'Query',
305305
fields: {
306306
pets: {
307-
type: new GraphQLList(PetType),
307+
type: GraphQLList(PetType),
308308
resolve() {
309309
return Promise.resolve([
310310
new Dog('Odie', true),
@@ -400,7 +400,7 @@ describe('Execute: Handles execution of abstract types with promises', () => {
400400
name: 'Query',
401401
fields: {
402402
pets: {
403-
type: new GraphQLList(PetType),
403+
type: GraphQLList(PetType),
404404
resolve() {
405405
return [
406406
new Dog('Odie', true),
@@ -489,7 +489,7 @@ describe('Execute: Handles execution of abstract types with promises', () => {
489489
name: 'Query',
490490
fields: {
491491
pets: {
492-
type: new GraphQLList(PetType),
492+
type: GraphQLList(PetType),
493493
resolve() {
494494
return [new Dog('Odie', true), new Cat('Garfield', false)];
495495
},
@@ -561,7 +561,7 @@ describe('Execute: Handles execution of abstract types with promises', () => {
561561
name: 'Query',
562562
fields: {
563563
pets: {
564-
type: new GraphQLList(PetType),
564+
type: GraphQLList(PetType),
565565
resolve() {
566566
return [new Dog('Odie', true), new Cat('Garfield', false)];
567567
},

src/execution/__tests__/abstract-test.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ describe('Execute: Handles execution of abstract types', () => {
7272
name: 'Query',
7373
fields: {
7474
pets: {
75-
type: new GraphQLList(PetType),
75+
type: GraphQLList(PetType),
7676
resolve() {
7777
return [new Dog('Odie', true), new Cat('Garfield', false)];
7878
},
@@ -141,7 +141,7 @@ describe('Execute: Handles execution of abstract types', () => {
141141
name: 'Query',
142142
fields: {
143143
pets: {
144-
type: new GraphQLList(PetType),
144+
type: GraphQLList(PetType),
145145
resolve() {
146146
return [new Dog('Odie', true), new Cat('Garfield', false)];
147147
},
@@ -226,7 +226,7 @@ describe('Execute: Handles execution of abstract types', () => {
226226
name: 'Query',
227227
fields: {
228228
pets: {
229-
type: new GraphQLList(PetType),
229+
type: GraphQLList(PetType),
230230
resolve() {
231231
return [
232232
new Dog('Odie', true),
@@ -320,7 +320,7 @@ describe('Execute: Handles execution of abstract types', () => {
320320
name: 'Query',
321321
fields: {
322322
pets: {
323-
type: new GraphQLList(PetType),
323+
type: GraphQLList(PetType),
324324
resolve() {
325325
return [
326326
new Dog('Odie', true),
@@ -407,7 +407,7 @@ describe('Execute: Handles execution of abstract types', () => {
407407
name: 'Query',
408408
fields: {
409409
pets: {
410-
type: new GraphQLList(PetType),
410+
type: GraphQLList(PetType),
411411
resolve() {
412412
return [new Dog('Odie', true), new Cat('Garfield', false)];
413413
},

src/execution/__tests__/executor-test.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,8 @@ describe('Execute: Handles basic execution tasks', () => {
202202
fields: {
203203
a: { type: GraphQLString },
204204
b: { type: GraphQLString },
205-
c: { type: new GraphQLList(GraphQLString) },
206-
deeper: { type: new GraphQLList(DataType) },
205+
c: { type: GraphQLList(GraphQLString) },
206+
deeper: { type: GraphQLList(DataType) },
207207
},
208208
});
209209

@@ -448,7 +448,7 @@ describe('Execute: Handles basic execution tasks', () => {
448448
syncError: { type: GraphQLString },
449449
syncRawError: { type: GraphQLString },
450450
syncReturnError: { type: GraphQLString },
451-
syncReturnErrorList: { type: new GraphQLList(GraphQLString) },
451+
syncReturnErrorList: { type: GraphQLList(GraphQLString) },
452452
async: { type: GraphQLString },
453453
asyncReject: { type: GraphQLString },
454454
asyncRawReject: { type: GraphQLString },
@@ -550,7 +550,7 @@ describe('Execute: Handles basic execution tasks', () => {
550550
name: 'Query',
551551
fields: {
552552
foods: {
553-
type: new GraphQLList(
553+
type: GraphQLList(
554554
new GraphQLObjectType({
555555
name: 'Food',
556556
fields: {
@@ -597,11 +597,11 @@ describe('Execute: Handles basic execution tasks', () => {
597597
resolve: () => ({}),
598598
},
599599
nonNullA: {
600-
type: new GraphQLNonNull(A),
600+
type: GraphQLNonNull(A),
601601
resolve: () => ({}),
602602
},
603603
throws: {
604-
type: new GraphQLNonNull(GraphQLString),
604+
type: GraphQLNonNull(GraphQLString),
605605
resolve: () => {
606606
throw new Error('Catch me if you can');
607607
},
@@ -1034,7 +1034,7 @@ describe('Execute: Handles basic execution tasks', () => {
10341034
name: 'Query',
10351035
fields: {
10361036
specials: {
1037-
type: new GraphQLList(SpecialType),
1037+
type: GraphQLList(SpecialType),
10381038
resolve: rootValue => rootValue.specials,
10391039
},
10401040
},

src/execution/__tests__/lists-test.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ describe('Execute: Accepts any iterable as list value', () => {
7070
it(
7171
'Accepts a Set as a List value',
7272
check(
73-
new GraphQLList(GraphQLString),
73+
GraphQLList(GraphQLString),
7474
new Set(['apple', 'banana', 'apple', 'coconut']),
7575
{ data: { nest: { test: ['apple', 'banana', 'coconut'] } } },
7676
),
@@ -84,7 +84,7 @@ describe('Execute: Accepts any iterable as list value', () => {
8484

8585
it(
8686
'Accepts an Generator function as a List value',
87-
check(new GraphQLList(GraphQLString), yieldItems(), {
87+
check(GraphQLList(GraphQLString), yieldItems(), {
8888
data: { nest: { test: ['one', '2', 'true'] } },
8989
}),
9090
);
@@ -95,14 +95,14 @@ describe('Execute: Accepts any iterable as list value', () => {
9595

9696
it(
9797
'Accepts function arguments as a List value',
98-
check(new GraphQLList(GraphQLString), getArgs('one', 'two'), {
98+
check(GraphQLList(GraphQLString), getArgs('one', 'two'), {
9999
data: { nest: { test: ['one', 'two'] } },
100100
}),
101101
);
102102

103103
it(
104104
'Does not accept (Iterable) String-literal as a List value',
105-
check(new GraphQLList(GraphQLString), 'Singluar', {
105+
check(GraphQLList(GraphQLString), 'Singluar', {
106106
data: { nest: { test: null } },
107107
errors: [
108108
{
@@ -118,7 +118,7 @@ describe('Execute: Accepts any iterable as list value', () => {
118118

119119
describe('Execute: Handles list nullability', () => {
120120
describe('[T]', () => {
121-
const type = new GraphQLList(GraphQLInt);
121+
const type = GraphQLList(GraphQLInt);
122122

123123
describe('Array<T>', () => {
124124
it(
@@ -203,7 +203,7 @@ describe('Execute: Handles list nullability', () => {
203203
});
204204

205205
describe('[T]!', () => {
206-
const type = new GraphQLNonNull(new GraphQLList(GraphQLInt));
206+
const type = GraphQLNonNull(GraphQLList(GraphQLInt));
207207

208208
describe('Array<T>', () => {
209209
it(
@@ -311,7 +311,7 @@ describe('Execute: Handles list nullability', () => {
311311
});
312312

313313
describe('[T!]', () => {
314-
const type = new GraphQLList(new GraphQLNonNull(GraphQLInt));
314+
const type = GraphQLList(GraphQLNonNull(GraphQLInt));
315315

316316
describe('Array<T>', () => {
317317
it(
@@ -422,9 +422,7 @@ describe('Execute: Handles list nullability', () => {
422422
});
423423

424424
describe('[T!]!', () => {
425-
const type = new GraphQLNonNull(
426-
new GraphQLList(new GraphQLNonNull(GraphQLInt)),
427-
);
425+
const type = GraphQLNonNull(GraphQLList(GraphQLNonNull(GraphQLInt)));
428426

429427
describe('Array<T>', () => {
430428
it(

src/execution/__tests__/nonnull-test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ const dataType = new GraphQLObjectType({
9898
name: 'DataType',
9999
fields: () => ({
100100
sync: { type: GraphQLString },
101-
nonNullSync: { type: new GraphQLNonNull(GraphQLString) },
101+
nonNullSync: { type: GraphQLNonNull(GraphQLString) },
102102
promise: { type: GraphQLString },
103-
nonNullPromise: { type: new GraphQLNonNull(GraphQLString) },
103+
nonNullPromise: { type: GraphQLNonNull(GraphQLString) },
104104
nest: { type: dataType },
105-
nonNullNest: { type: new GraphQLNonNull(dataType) },
105+
nonNullNest: { type: GraphQLNonNull(dataType) },
106106
promiseNest: { type: dataType },
107-
nonNullPromiseNest: { type: new GraphQLNonNull(dataType) },
107+
nonNullPromiseNest: { type: GraphQLNonNull(dataType) },
108108
}),
109109
});
110110
const schema = new GraphQLSchema({

src/execution/__tests__/schema-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ describe('Execute: Handles execution with a complex schema', () => {
4949
const BlogArticle = new GraphQLObjectType({
5050
name: 'Article',
5151
fields: {
52-
id: { type: new GraphQLNonNull(GraphQLString) },
52+
id: { type: GraphQLNonNull(GraphQLString) },
5353
isPublished: { type: GraphQLBoolean },
5454
author: { type: BlogAuthor },
5555
title: { type: GraphQLString },
5656
body: { type: GraphQLString },
57-
keywords: { type: new GraphQLList(GraphQLString) },
57+
keywords: { type: GraphQLList(GraphQLString) },
5858
},
5959
});
6060

@@ -67,7 +67,7 @@ describe('Execute: Handles execution with a complex schema', () => {
6767
resolve: (_, { id }) => article(id),
6868
},
6969
feed: {
70-
type: new GraphQLList(BlogArticle),
70+
type: GraphQLList(BlogArticle),
7171
resolve: () => [
7272
article(1),
7373
article(2),

src/execution/__tests__/union-interface-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ const PersonType = new GraphQLObjectType({
8787
interfaces: [NamedType],
8888
fields: {
8989
name: { type: GraphQLString },
90-
pets: { type: new GraphQLList(PetType) },
91-
friends: { type: new GraphQLList(NamedType) },
90+
pets: { type: GraphQLList(PetType) },
91+
friends: { type: GraphQLList(NamedType) },
9292
},
9393
isTypeOf: value => value instanceof Person,
9494
});
@@ -341,7 +341,7 @@ describe('Execute: Union and intersection types', () => {
341341
interfaces: [NamedType2],
342342
fields: {
343343
name: { type: GraphQLString },
344-
friends: { type: new GraphQLList(NamedType2) },
344+
friends: { type: GraphQLList(NamedType2) },
345345
},
346346
});
347347

0 commit comments

Comments
 (0)