Skip to content

Commit 62d1b75

Browse files
committed
Stricter types: semantic non null may only wrap output types
1 parent 88c5d93 commit 62d1b75

File tree

4 files changed

+29
-20
lines changed

4 files changed

+29
-20
lines changed

src/type/definition.ts

+12-17
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,7 @@ export type GraphQLType =
7373
| GraphQLInterfaceType
7474
| GraphQLUnionType
7575
| GraphQLEnumType
76-
| GraphQLInputObjectType
77-
| GraphQLList<GraphQLType>
76+
| GraphQLList<GraphQLOutputType>
7877
>;
7978

8079
export function isType(type: unknown): type is GraphQLType {
@@ -213,24 +212,15 @@ export function assertNonNullType(type: unknown): GraphQLNonNull<GraphQLType> {
213212
return type;
214213
}
215214

216-
export function isSemanticNonNullType(
217-
type: GraphQLInputType,
218-
): type is GraphQLSemanticNonNull<GraphQLInputType>;
219-
export function isSemanticNonNullType(
220-
type: GraphQLOutputType,
221-
): type is GraphQLSemanticNonNull<GraphQLOutputType>;
222-
export function isSemanticNonNullType(
223-
type: unknown,
224-
): type is GraphQLSemanticNonNull<GraphQLType>;
225215
export function isSemanticNonNullType(
226216
type: unknown,
227-
): type is GraphQLSemanticNonNull<GraphQLType> {
217+
): type is GraphQLSemanticNonNull<GraphQLNullableType & GraphQLOutputType> {
228218
return instanceOf(type, GraphQLSemanticNonNull);
229219
}
230220

231221
export function assertSemanticNonNullType(
232222
type: unknown,
233-
): GraphQLSemanticNonNull<GraphQLType> {
223+
): GraphQLSemanticNonNull<GraphQLNullableType & GraphQLOutputType> {
234224
if (!isSemanticNonNullType(type)) {
235225
throw new Error(
236226
`Expected ${inspect(type)} to be a GraphQL Semantic-Non-Null type.`,
@@ -485,7 +475,9 @@ export class GraphQLNonNull<T extends GraphQLNullableType> {
485475
*
486476
* @experimental
487477
*/
488-
export class GraphQLSemanticNonNull<T extends GraphQLNullableType> {
478+
export class GraphQLSemanticNonNull<
479+
T extends GraphQLNullableType & GraphQLOutputType,
480+
> {
489481
readonly ofType: T;
490482

491483
constructor(ofType: T) {
@@ -516,8 +508,8 @@ export class GraphQLSemanticNonNull<T extends GraphQLNullableType> {
516508

517509
export type GraphQLWrappingType =
518510
| GraphQLList<GraphQLType>
519-
| GraphQLNonNull<GraphQLType>
520-
| GraphQLSemanticNonNull<GraphQLType>;
511+
| GraphQLNonNull<GraphQLNullableType>
512+
| GraphQLSemanticNonNull<GraphQLNullableType & GraphQLOutputType>;
521513

522514
export function isWrappingType(type: unknown): type is GraphQLWrappingType {
523515
return isListType(type) || isNonNullType(type) || isSemanticNonNullType(type);
@@ -555,7 +547,10 @@ export function assertNullableType(type: unknown): GraphQLNullableType {
555547

556548
export function getNullableType(type: undefined | null): void;
557549
export function getNullableType<T extends GraphQLNullableType>(
558-
type: T | GraphQLNonNull<T> | GraphQLSemanticNonNull<T>,
550+
type:
551+
| T
552+
| GraphQLNonNull<T>
553+
| GraphQLSemanticNonNull<T extends GraphQLOutputType ? T : never>,
559554
): T;
560555
export function getNullableType(
561556
type: Maybe<GraphQLType>,

src/utilities/buildClientSchema.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,13 @@ export function buildClientSchema(
143143
if (!nullableRef) {
144144
throw new Error('Decorated type deeper than introspection query.');
145145
}
146-
const nullableType = getType(nullableRef);
147-
return new GraphQLSemanticNonNull(assertNullableType(nullableType));
146+
const nullableType = assertNullableType(getType(nullableRef));
147+
if (!isOutputType(nullableType)) {
148+
throw new Error(
149+
'A semantic non-null wrapper must wrap an output type.',
150+
);
151+
}
152+
return new GraphQLSemanticNonNull(nullableType);
148153
}
149154
return getNamedType(typeRef);
150155
}

src/utilities/extendSchema.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ import {
6161
isListType,
6262
isNonNullType,
6363
isObjectType,
64+
isOutputType,
6465
isScalarType,
6566
isSemanticNonNullType,
6667
isUnionType,
@@ -439,7 +440,11 @@ export function extendSchemaImpl(
439440
return new GraphQLNonNull(getWrappedType(node.type));
440441
}
441442
if (node.kind === Kind.SEMANTIC_NON_NULL_TYPE) {
442-
return new GraphQLSemanticNonNull(getWrappedType(node.type));
443+
const wrapped = getWrappedType(node.type);
444+
if (!isOutputType(wrapped)) {
445+
throw new Error('A semantic non-null type cannot wrap an input type.');
446+
}
447+
return new GraphQLSemanticNonNull(wrapped);
443448
}
444449
return getNamedType(node);
445450
}

src/utilities/typeFromAST.ts

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
GraphQLList,
1212
GraphQLNonNull,
1313
GraphQLSemanticNonNull,
14+
isOutputType,
1415
} from '../type/definition';
1516
import type { GraphQLSchema } from '../type/schema';
1617

@@ -52,6 +53,9 @@ export function typeFromAST(
5253
}
5354
case Kind.SEMANTIC_NON_NULL_TYPE: {
5455
const innerType = typeFromAST(schema, typeNode.type);
56+
if (!isOutputType(innerType)) {
57+
throw new Error('A semantic non-null type must wrap an output type.');
58+
}
5559
return innerType && new GraphQLSemanticNonNull(innerType);
5660
}
5761
case Kind.NAMED_TYPE:

0 commit comments

Comments
 (0)