Skip to content

Commit cb12939

Browse files
committed
feat: replace instanceOf with unique Symbol checks
1 parent b91f51b commit cb12939

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';
@@ -72,11 +71,17 @@ export function assertType(type: unknown): GraphQLType {
7271
return type;
7372
}
7473

74+
const isGraphQLScalarTypeSymbol = Symbol.for('GraphQLScalarType');
75+
7576
/**
7677
* There are predicates for each kind of GraphQL type.
7778
*/
7879
export function isScalarType(type: unknown): type is GraphQLScalarType {
79-
return instanceOf(type, GraphQLScalarType);
80+
return (
81+
typeof type === 'object' &&
82+
type != null &&
83+
isGraphQLScalarTypeSymbol in type
84+
);
8085
}
8186

8287
export function assertScalarType(type: unknown): GraphQLScalarType {
@@ -86,8 +91,14 @@ export function assertScalarType(type: unknown): GraphQLScalarType {
8691
return type;
8792
}
8893

94+
const isGraphQLObjectTypeSymbol = Symbol.for('GraphQLObjectType');
95+
8996
export function isObjectType(type: unknown): type is GraphQLObjectType {
90-
return instanceOf(type, GraphQLObjectType);
97+
return (
98+
typeof type === 'object' &&
99+
type != null &&
100+
isGraphQLObjectTypeSymbol in type
101+
);
91102
}
92103

93104
export function assertObjectType(type: unknown): GraphQLObjectType {
@@ -97,8 +108,14 @@ export function assertObjectType(type: unknown): GraphQLObjectType {
97108
return type;
98109
}
99110

111+
const isGraphQLInterfaceTypeSymbol = Symbol.for('GraphQLInterfaceType');
112+
100113
export function isInterfaceType(type: unknown): type is GraphQLInterfaceType {
101-
return instanceOf(type, GraphQLInterfaceType);
114+
return (
115+
typeof type === 'object' &&
116+
type != null &&
117+
isGraphQLInterfaceTypeSymbol in type
118+
);
102119
}
103120

104121
export function assertInterfaceType(type: unknown): GraphQLInterfaceType {
@@ -110,8 +127,12 @@ export function assertInterfaceType(type: unknown): GraphQLInterfaceType {
110127
return type;
111128
}
112129

130+
const isGraphQLUnionTypeSymbol = Symbol.for('GraphQLUnionType');
131+
113132
export function isUnionType(type: unknown): type is GraphQLUnionType {
114-
return instanceOf(type, GraphQLUnionType);
133+
return (
134+
typeof type === 'object' && type != null && isGraphQLUnionTypeSymbol in type
135+
);
115136
}
116137

117138
export function assertUnionType(type: unknown): GraphQLUnionType {
@@ -121,8 +142,12 @@ export function assertUnionType(type: unknown): GraphQLUnionType {
121142
return type;
122143
}
123144

145+
const isGraphQLEnumTypeSymbol = Symbol.for('GraphQLEnumType');
146+
124147
export function isEnumType(type: unknown): type is GraphQLEnumType {
125-
return instanceOf(type, GraphQLEnumType);
148+
return (
149+
typeof type === 'object' && type != null && isGraphQLEnumTypeSymbol in type
150+
);
126151
}
127152

128153
export function assertEnumType(type: unknown): GraphQLEnumType {
@@ -132,10 +157,16 @@ export function assertEnumType(type: unknown): GraphQLEnumType {
132157
return type;
133158
}
134159

160+
const isGraphQLInputObjectTypeSymbol = Symbol.for('GraphQLInputObjectType');
161+
135162
export function isInputObjectType(
136163
type: unknown,
137164
): type is GraphQLInputObjectType {
138-
return instanceOf(type, GraphQLInputObjectType);
165+
return (
166+
typeof type === 'object' &&
167+
type != null &&
168+
isGraphQLInputObjectTypeSymbol in type
169+
);
139170
}
140171

141172
export function assertInputObjectType(type: unknown): GraphQLInputObjectType {
@@ -147,6 +178,8 @@ export function assertInputObjectType(type: unknown): GraphQLInputObjectType {
147178
return type;
148179
}
149180

181+
const isGraphQLListTypeSymbol = Symbol.for('GraphQLListType');
182+
150183
export function isListType(
151184
type: GraphQLInputType,
152185
): type is GraphQLList<GraphQLInputType>;
@@ -155,7 +188,9 @@ export function isListType(
155188
): type is GraphQLList<GraphQLOutputType>;
156189
export function isListType(type: unknown): type is GraphQLList<GraphQLType>;
157190
export function isListType(type: unknown): type is GraphQLList<GraphQLType> {
158-
return instanceOf(type, GraphQLList);
191+
return (
192+
typeof type === 'object' && type != null && isGraphQLListTypeSymbol in type
193+
);
159194
}
160195

161196
export function assertListType(type: unknown): GraphQLList<GraphQLType> {
@@ -165,6 +200,8 @@ export function assertListType(type: unknown): GraphQLList<GraphQLType> {
165200
return type;
166201
}
167202

203+
const isGraphQLNonNullTypeSymbol = Symbol.for('GraphQLNonNullType');
204+
168205
export function isNonNullType(
169206
type: GraphQLInputType,
170207
): type is GraphQLNonNull<GraphQLNullableInputType>;
@@ -177,7 +214,11 @@ export function isNonNullType(
177214
export function isNonNullType(
178215
type: unknown,
179216
): type is GraphQLNonNull<GraphQLNullableType> {
180-
return instanceOf(type, GraphQLNonNull);
217+
return (
218+
typeof type === 'object' &&
219+
type != null &&
220+
isGraphQLNonNullTypeSymbol in type
221+
);
181222
}
182223

183224
export function assertNonNullType(
@@ -318,6 +359,7 @@ export function assertAbstractType(type: unknown): GraphQLAbstractType {
318359
* ```
319360
*/
320361
export class GraphQLList<T extends GraphQLType> {
362+
readonly [isGraphQLListTypeSymbol]: true = true;
321363
readonly ofType: T;
322364

323365
constructor(ofType: T) {
@@ -364,6 +406,7 @@ export class GraphQLList<T extends GraphQLType> {
364406
* Note: the enforcement of non-nullability occurs within the executor.
365407
*/
366408
export class GraphQLNonNull<T extends GraphQLNullableType> {
409+
readonly [isGraphQLNonNullTypeSymbol]: true = true;
367410
readonly ofType: T;
368411

369412
constructor(ofType: T) {
@@ -554,6 +597,7 @@ export interface GraphQLScalarTypeExtensions {
554597
* ```
555598
*/
556599
export class GraphQLScalarType<TInternal = unknown, TExternal = TInternal> {
600+
readonly [isGraphQLScalarTypeSymbol]: true = true;
557601
name: string;
558602
description: Maybe<string>;
559603
specifiedByURL: Maybe<string>;
@@ -724,6 +768,7 @@ export interface GraphQLObjectTypeExtensions<_TSource = any, _TContext = any> {
724768
* ```
725769
*/
726770
export class GraphQLObjectType<TSource = any, TContext = any> {
771+
readonly [isGraphQLObjectTypeSymbol]: true = true;
727772
name: string;
728773
description: Maybe<string>;
729774
isTypeOf: Maybe<GraphQLIsTypeOfFn<TSource, TContext>>;
@@ -1077,6 +1122,7 @@ export interface GraphQLInterfaceTypeExtensions {
10771122
* ```
10781123
*/
10791124
export class GraphQLInterfaceType {
1125+
readonly [isGraphQLInterfaceTypeSymbol]: true = true;
10801126
name: string;
10811127
description: Maybe<string>;
10821128
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
@@ -1206,6 +1252,7 @@ export interface GraphQLUnionTypeExtensions {
12061252
* ```
12071253
*/
12081254
export class GraphQLUnionType {
1255+
readonly [isGraphQLUnionTypeSymbol]: true = true;
12091256
name: string;
12101257
description: Maybe<string>;
12111258
resolveType: Maybe<GraphQLTypeResolver<any, any>>;
@@ -1333,6 +1380,7 @@ export interface GraphQLEnumTypeExtensions {
13331380
* will be used as its internal value.
13341381
*/
13351382
export class GraphQLEnumType /* <T> */ {
1383+
readonly [isGraphQLEnumTypeSymbol]: true = true;
13361384
name: string;
13371385
description: Maybe<string>;
13381386
extensions: Readonly<GraphQLEnumTypeExtensions>;
@@ -1573,6 +1621,7 @@ export interface GraphQLInputObjectTypeExtensions {
15731621
* ```
15741622
*/
15751623
export class GraphQLInputObjectType {
1624+
readonly [isGraphQLInputObjectTypeSymbol]: true = true;
15761625
name: string;
15771626
description: Maybe<string>;
15781627
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)