Skip to content

Commit b71648f

Browse files
committed
feat: replace instanceOf with unique Symbol checks
1 parent 540bb38 commit b71648f

File tree

8 files changed

+93
-21
lines changed

8 files changed

+93
-21
lines changed

src/error/GraphQLError.ts

+9
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,22 @@ export interface GraphQLErrorOptions {
2929
extensions?: Maybe<GraphQLErrorExtensions>;
3030
}
3131

32+
const isGraphQLErrorSymbol = Symbol.for('GraphQLError');
33+
34+
export function isGraphQLError(error: unknown): error is GraphQLError {
35+
return (
36+
typeof error === 'object' && error != null && isGraphQLErrorSymbol in error
37+
);
38+
}
39+
3240
/**
3341
* A GraphQLError describes an Error found during the parse, validate, or
3442
* execute phases of performing a GraphQL operation. In addition to a message
3543
* and stack trace, it also includes information about the locations in a
3644
* GraphQL document and/or execution result that correspond to the Error.
3745
*/
3846
export class GraphQLError extends Error {
47+
[isGraphQLErrorSymbol]: true = true;
3948
/**
4049
* An array of `{ line, column }` locations within the source GraphQL document
4150
* which correspond to this error.

src/execution/subscribe.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { isAsyncIterable } from '../jsutils/isAsyncIterable';
33
import type { Maybe } from '../jsutils/Maybe';
44
import { addPath, pathToArray } from '../jsutils/Path';
55

6-
import { GraphQLError } from '../error/GraphQLError';
6+
import { GraphQLError, isGraphQLError } from '../error/GraphQLError';
77
import { locatedError } from '../error/locatedError';
88

99
import type { DocumentNode } from '../language/ast';
@@ -169,7 +169,7 @@ export async function createSourceEventStream(
169169
} catch (error) {
170170
// If it GraphQLError, report it as an ExecutionResult, containing only errors and no data.
171171
// Otherwise treat the error as a system-class error and re-throw it.
172-
if (error instanceof GraphQLError) {
172+
if (isGraphQLError(error)) {
173173
return { errors: [error] };
174174
}
175175
throw error;

src/language/source.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { devAssert } from '../jsutils/devAssert';
22
import { inspect } from '../jsutils/inspect';
3-
import { instanceOf } from '../jsutils/instanceOf';
43

54
interface Location {
65
line: number;
76
column: number;
87
}
98

9+
const isSourceSymbol = Symbol.for('Source');
10+
1011
/**
1112
* A representation of source input to GraphQL. The `name` and `locationOffset` parameters are
1213
* optional, but they are useful for clients who store GraphQL documents in source files.
@@ -15,6 +16,7 @@ interface Location {
1516
* The `line` and `column` properties in `locationOffset` are 1-indexed.
1617
*/
1718
export class Source {
19+
[isSourceSymbol]: true = true;
1820
body: string;
1921
name: string;
2022
locationOffset: Location;
@@ -53,5 +55,7 @@ export class Source {
5355
* @internal
5456
*/
5557
export function isSource(source: unknown): source is Source {
56-
return instanceOf(source, Source);
58+
return (
59+
typeof source === 'object' && source != null && isSourceSymbol in source
60+
);
5761
}

src/type/definition.ts

+58-9
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { devAssert } from '../jsutils/devAssert';
22
import { didYouMean } from '../jsutils/didYouMean';
33
import { identityFunc } from '../jsutils/identityFunc';
44
import { inspect } from '../jsutils/inspect';
5-
import { instanceOf } from '../jsutils/instanceOf';
65
import { isObjectLike } from '../jsutils/isObjectLike';
76
import { keyMap } from '../jsutils/keyMap';
87
import { keyValMap } from '../jsutils/keyValMap';
@@ -75,11 +74,17 @@ export function assertType(type: unknown): GraphQLType {
7574
return type;
7675
}
7776

77+
const isGraphQLScalarTypeSymbol = Symbol.for('GraphQLScalarType');
78+
7879
/**
7980
* There are predicates for each kind of GraphQL type.
8081
*/
8182
export function isScalarType(type: unknown): type is GraphQLScalarType {
82-
return instanceOf(type, GraphQLScalarType);
83+
return (
84+
typeof type === 'object' &&
85+
type != null &&
86+
isGraphQLScalarTypeSymbol in type
87+
);
8388
}
8489

8590
export function assertScalarType(type: unknown): GraphQLScalarType {
@@ -89,8 +94,14 @@ export function assertScalarType(type: unknown): GraphQLScalarType {
8994
return type;
9095
}
9196

97+
const isGraphQLObjectTypeSymbol = Symbol.for('GraphQLObjectType');
98+
9299
export function isObjectType(type: unknown): type is GraphQLObjectType {
93-
return instanceOf(type, GraphQLObjectType);
100+
return (
101+
typeof type === 'object' &&
102+
type != null &&
103+
isGraphQLObjectTypeSymbol in type
104+
);
94105
}
95106

96107
export function assertObjectType(type: unknown): GraphQLObjectType {
@@ -100,8 +111,14 @@ export function assertObjectType(type: unknown): GraphQLObjectType {
100111
return type;
101112
}
102113

114+
const isGraphQLInterfaceTypeSymbol = Symbol.for('GraphQLInterfaceType');
115+
103116
export function isInterfaceType(type: unknown): type is GraphQLInterfaceType {
104-
return instanceOf(type, GraphQLInterfaceType);
117+
return (
118+
typeof type === 'object' &&
119+
type != null &&
120+
isGraphQLInterfaceTypeSymbol in type
121+
);
105122
}
106123

107124
export function assertInterfaceType(type: unknown): GraphQLInterfaceType {
@@ -113,8 +130,12 @@ export function assertInterfaceType(type: unknown): GraphQLInterfaceType {
113130
return type;
114131
}
115132

133+
const isGraphQLUnionTypeSymbol = Symbol.for('GraphQLUnionType');
134+
116135
export function isUnionType(type: unknown): type is GraphQLUnionType {
117-
return instanceOf(type, GraphQLUnionType);
136+
return (
137+
typeof type === 'object' && type != null && isGraphQLUnionTypeSymbol in type
138+
);
118139
}
119140

120141
export function assertUnionType(type: unknown): GraphQLUnionType {
@@ -124,8 +145,12 @@ export function assertUnionType(type: unknown): GraphQLUnionType {
124145
return type;
125146
}
126147

148+
const isGraphQLEnumTypeSymbol = Symbol.for('GraphQLEnumType');
149+
127150
export function isEnumType(type: unknown): type is GraphQLEnumType {
128-
return instanceOf(type, GraphQLEnumType);
151+
return (
152+
typeof type === 'object' && type != null && isGraphQLEnumTypeSymbol in type
153+
);
129154
}
130155

131156
export function assertEnumType(type: unknown): GraphQLEnumType {
@@ -135,10 +160,16 @@ export function assertEnumType(type: unknown): GraphQLEnumType {
135160
return type;
136161
}
137162

163+
const isGraphQLInputObjectTypeSymbol = Symbol.for('GraphQLInputObjectType');
164+
138165
export function isInputObjectType(
139166
type: unknown,
140167
): type is GraphQLInputObjectType {
141-
return instanceOf(type, GraphQLInputObjectType);
168+
return (
169+
typeof type === 'object' &&
170+
type != null &&
171+
isGraphQLInputObjectTypeSymbol in type
172+
);
142173
}
143174

144175
export function assertInputObjectType(type: unknown): GraphQLInputObjectType {
@@ -150,6 +181,8 @@ export function assertInputObjectType(type: unknown): GraphQLInputObjectType {
150181
return type;
151182
}
152183

184+
const isGraphQLListTypeSymbol = Symbol.for('GraphQLListType');
185+
153186
export function isListType(
154187
type: GraphQLInputType,
155188
): type is GraphQLList<GraphQLInputType>;
@@ -158,7 +191,9 @@ export function isListType(
158191
): type is GraphQLList<GraphQLOutputType>;
159192
export function isListType(type: unknown): type is GraphQLList<GraphQLType>;
160193
export function isListType(type: unknown): type is GraphQLList<GraphQLType> {
161-
return instanceOf(type, GraphQLList);
194+
return (
195+
typeof type === 'object' && type != null && isGraphQLListTypeSymbol in type
196+
);
162197
}
163198

164199
export function assertListType(type: unknown): GraphQLList<GraphQLType> {
@@ -168,6 +203,8 @@ export function assertListType(type: unknown): GraphQLList<GraphQLType> {
168203
return type;
169204
}
170205

206+
const isGraphQLNonNullTypeSymbol = Symbol.for('GraphQLNonNullType');
207+
171208
export function isNonNullType(
172209
type: GraphQLInputType,
173210
): type is GraphQLNonNull<GraphQLNullableInputType>;
@@ -180,7 +217,11 @@ export function isNonNullType(
180217
export function isNonNullType(
181218
type: unknown,
182219
): type is GraphQLNonNull<GraphQLNullableType> {
183-
return instanceOf(type, GraphQLNonNull);
220+
return (
221+
typeof type === 'object' &&
222+
type != null &&
223+
isGraphQLNonNullTypeSymbol in type
224+
);
184225
}
185226

186227
export function assertNonNullType(type: unknown): GraphQLNonNull<GraphQLType> {
@@ -319,6 +360,7 @@ export function assertAbstractType(type: unknown): GraphQLAbstractType {
319360
* ```
320361
*/
321362
export class GraphQLList<T extends GraphQLType> {
363+
readonly [isGraphQLListTypeSymbol]: true = true;
322364
readonly ofType: T;
323365

324366
constructor(ofType: T) {
@@ -365,6 +407,7 @@ export class GraphQLList<T extends GraphQLType> {
365407
* Note: the enforcement of non-nullability occurs within the executor.
366408
*/
367409
export class GraphQLNonNull<T extends GraphQLNullableType> {
410+
readonly [isGraphQLNonNullTypeSymbol]: true = true;
368411
readonly ofType: T;
369412

370413
constructor(ofType: T) {
@@ -555,6 +598,7 @@ export interface GraphQLScalarTypeExtensions {
555598
* ```
556599
*/
557600
export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
601+
readonly [isGraphQLScalarTypeSymbol]: true = true;
558602
name: string;
559603
description: Maybe<string>;
560604
specifiedByURL: Maybe<string>;
@@ -725,6 +769,7 @@ export interface GraphQLObjectTypeExtensions<_TSource = any, _TContext = any> {
725769
* ```
726770
*/
727771
export class GraphQLObjectType<TSource = any, TContext = any> {
772+
readonly [isGraphQLObjectTypeSymbol]: true = true;
728773
name: string;
729774
description: Maybe<string>;
730775
isTypeOf: Maybe<GraphQLIsTypeOfFn<TSource, TContext>>;
@@ -1078,6 +1123,7 @@ export interface GraphQLInterfaceTypeExtensions {
10781123
* ```
10791124
*/
10801125
export class GraphQLInterfaceType {
1126+
readonly [isGraphQLInterfaceTypeSymbol]: true = true;
10811127
name: string;
10821128
description: Maybe<string>;
10831129
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
@@ -1207,6 +1253,7 @@ export interface GraphQLUnionTypeExtensions {
12071253
* ```
12081254
*/
12091255
export class GraphQLUnionType {
1256+
readonly [isGraphQLUnionTypeSymbol]: true = true;
12101257
name: string;
12111258
description: Maybe<string>;
12121259
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
@@ -1334,6 +1381,7 @@ export interface GraphQLEnumTypeExtensions {
13341381
* will be used as its internal value.
13351382
*/
13361383
export class GraphQLEnumType /* <T> */ {
1384+
readonly [isGraphQLEnumTypeSymbol]: true = true;
13371385
name: string;
13381386
description: Maybe<string>;
13391387
extensions: Readonly<GraphQLEnumTypeExtensions>;
@@ -1574,6 +1622,7 @@ export interface GraphQLInputObjectTypeExtensions {
15741622
* ```
15751623
*/
15761624
export class GraphQLInputObjectType {
1625+
readonly [isGraphQLInputObjectTypeSymbol]: true = true;
15771626
name: string;
15781627
description: Maybe<string>;
15791628
extensions: Readonly<GraphQLInputObjectTypeExtensions>;

src/type/directives.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { devAssert } from '../jsutils/devAssert';
22
import { inspect } from '../jsutils/inspect';
3-
import { instanceOf } from '../jsutils/instanceOf';
43
import { isObjectLike } from '../jsutils/isObjectLike';
54
import type { Maybe } from '../jsutils/Maybe';
65
import { toObjMap } from '../jsutils/toObjMap';
@@ -24,7 +23,11 @@ import { GraphQLBoolean, GraphQLString } from './scalars';
2423
* Test if the given value is a GraphQL directive.
2524
*/
2625
export function isDirective(directive: unknown): directive is GraphQLDirective {
27-
return instanceOf(directive, GraphQLDirective);
26+
return (
27+
typeof directive === 'object' &&
28+
directive != null &&
29+
isGraphQLDirectiveSymbol in directive
30+
);
2831
}
2932

3033
export function assertDirective(directive: unknown): GraphQLDirective {
@@ -49,11 +52,14 @@ export interface GraphQLDirectiveExtensions {
4952
[attributeName: string]: unknown;
5053
}
5154

55+
const isGraphQLDirectiveSymbol = Symbol.for('GraphQLDirective');
56+
5257
/**
5358
* Directives are used by the GraphQL runtime as a way of modifying execution
5459
* behavior. Type system creators will usually not create these directly.
5560
*/
5661
export class GraphQLDirective {
62+
[isGraphQLDirectiveSymbol]: true = true;
5763
name: string;
5864
description: Maybe<string>;
5965
locations: ReadonlyArray<DirectiveLocation>;

src/type/schema.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { devAssert } from '../jsutils/devAssert';
22
import { inspect } from '../jsutils/inspect';
3-
import { instanceOf } from '../jsutils/instanceOf';
43
import { isObjectLike } from '../jsutils/isObjectLike';
54
import type { Maybe } from '../jsutils/Maybe';
65
import type { ObjMap } from '../jsutils/ObjMap';
@@ -43,7 +42,9 @@ import {
4342
* Test if the given value is a GraphQL schema.
4443
*/
4544
export function isSchema(schema: unknown): schema is GraphQLSchema {
46-
return instanceOf(schema, GraphQLSchema);
45+
return (
46+
typeof schema === 'object' && schema != null && isSchemaSymbol in schema
47+
);
4748
}
4849

4950
export function assertSchema(schema: unknown): GraphQLSchema {
@@ -66,6 +67,8 @@ export interface GraphQLSchemaExtensions {
6667
[attributeName: string]: unknown;
6768
}
6869

70+
const isSchemaSymbol = Symbol.for('GraphQLSchema');
71+
6972
/**
7073
* Schema Definition
7174
*
@@ -139,6 +142,7 @@ export class GraphQLSchema {
139142
extensions: Readonly<GraphQLSchemaExtensions>;
140143
astNode: Maybe<SchemaDefinitionNode>;
141144
extensionASTNodes: ReadonlyArray<SchemaExtensionNode>;
145+
[isSchemaSymbol]: true = true;
142146

143147
// Used as a cache for validateSchema().
144148
__validationErrors: Maybe<ReadonlyArray<GraphQLError>>;

src/utilities/coerceInputValue.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { addPath, pathToArray } from '../jsutils/Path';
88
import { printPathArray } from '../jsutils/printPathArray';
99
import { suggestionList } from '../jsutils/suggestionList';
1010

11-
import { GraphQLError } from '../error/GraphQLError';
11+
import { GraphQLError, isGraphQLError } from '../error/GraphQLError';
1212

1313
import type { GraphQLInputType } from '../type/definition';
1414
import {
@@ -154,7 +154,7 @@ function coerceInputValueImpl(
154154
try {
155155
parseResult = type.parseValue(inputValue);
156156
} catch (error) {
157-
if (error instanceof GraphQLError) {
157+
if (isGraphQLError(error)) {
158158
onError(pathToArray(path), inputValue, error);
159159
} else {
160160
onError(

src/validation/rules/ValuesOfCorrectTypeRule.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { inspect } from '../../jsutils/inspect';
33
import { keyMap } from '../../jsutils/keyMap';
44
import { suggestionList } from '../../jsutils/suggestionList';
55

6-
import { GraphQLError } from '../../error/GraphQLError';
6+
import { GraphQLError, isGraphQLError } from '../../error/GraphQLError';
77

88
import type { ValueNode } from '../../language/ast';
99
import { print } from '../../language/printer';
@@ -138,7 +138,7 @@ function isValidValueNode(context: ValidationContext, node: ValueNode): void {
138138
}
139139
} catch (error) {
140140
const typeStr = inspect(locationType);
141-
if (error instanceof GraphQLError) {
141+
if (isGraphQLError(error)) {
142142
context.reportError(error);
143143
} else {
144144
context.reportError(

0 commit comments

Comments
 (0)