Skip to content

Commit 5c673b9

Browse files
committed
use toStringTag as type brand
1 parent cfb5e91 commit 5c673b9

File tree

8 files changed

+114
-95
lines changed

8 files changed

+114
-95
lines changed

src/jsutils/__tests__/instanceOf-test.ts

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@ import { instanceOf } from '../instanceOf.js';
66
describe('instanceOf', () => {
77
it('do not throw on values without prototype', () => {
88
class Foo {
9-
readonly __isFoo = true as const;
109
get [Symbol.toStringTag]() {
1110
return 'Foo';
1211
}
1312
}
1413

15-
expect(instanceOf(undefined, true, Foo)).to.equal(false);
16-
expect(instanceOf(undefined, null, Foo)).to.equal(false);
17-
expect(instanceOf(undefined, Object.create(null), Foo)).to.equal(false);
14+
expect(instanceOf(false, true, Foo)).to.equal(false);
15+
expect(instanceOf(false, null, Foo)).to.equal(false);
16+
expect(instanceOf(false, Object.create(null), Foo)).to.equal(false);
1817
});
1918

2019
it('detect name clashes with older versions of this lib', () => {
@@ -25,7 +24,6 @@ describe('instanceOf', () => {
2524

2625
function newVersion() {
2726
class Foo {
28-
readonly __isFoo = true as const;
2927
get [Symbol.toStringTag]() {
3028
return 'Foo';
3129
}
@@ -36,16 +34,13 @@ describe('instanceOf', () => {
3634
const NewClass = newVersion();
3735
const OldClass = oldVersion();
3836
const newInstance = new NewClass();
39-
expect(instanceOf(newInstance.__isFoo, newInstance, NewClass)).to.equal(
40-
true,
41-
);
42-
expect(() => instanceOf(undefined, new OldClass(), NewClass)).to.throw();
37+
expect(instanceOf(true, newInstance, NewClass)).to.equal(true);
38+
expect(() => instanceOf(false, new OldClass(), NewClass)).to.throw();
4339
});
4440

4541
it('allows instances to have share the same constructor name', () => {
4642
function getMinifiedClass(tag: string) {
4743
class SomeNameAfterMinification {
48-
readonly [tag] = true as const;
4944
get [Symbol.toStringTag]() {
5045
return tag;
5146
}
@@ -57,23 +52,17 @@ describe('instanceOf', () => {
5752
const Bar = getMinifiedClass('Bar');
5853
const fooInstance = new Foo();
5954
const barInstance = new Bar();
60-
expect(instanceOf(fooInstance.foo, fooInstance, Bar)).to.equal(false);
61-
expect(instanceOf(barInstance.bar, barInstance, Foo)).to.equal(false);
55+
expect(instanceOf(false, fooInstance, Bar)).to.equal(false);
56+
expect(instanceOf(false, barInstance, Foo)).to.equal(false);
6257

6358
const DuplicateOfFoo = getMinifiedClass('Foo');
64-
const duplicateOfFooInstance = new DuplicateOfFoo();
65-
expect(() =>
66-
instanceOf(duplicateOfFooInstance.foo, new DuplicateOfFoo(), Foo),
67-
).to.throw();
68-
expect(() =>
69-
instanceOf(fooInstance.foo, fooInstance, DuplicateOfFoo),
70-
).to.throw();
59+
expect(() => instanceOf(true, new DuplicateOfFoo(), Foo)).to.throw();
60+
expect(() => instanceOf(true, fooInstance, DuplicateOfFoo)).to.throw();
7161
});
7262

7363
it('fails with descriptive error message', () => {
7464
function getFoo() {
7565
class Foo {
76-
readonly __isFoo = true as const;
7766
get [Symbol.toStringTag]() {
7867
return 'Foo';
7968
}
@@ -86,11 +75,11 @@ describe('instanceOf', () => {
8675
const foo1Instance = new Foo1();
8776
const foo2Instance = new Foo2();
8877

89-
expect(() => instanceOf(foo1Instance.__isFoo, foo1Instance, Foo2)).to.throw(
90-
/^Cannot use Foo "{ __isFoo: true }" from another module or realm./m,
78+
expect(() => instanceOf(true, foo1Instance, Foo2)).to.throw(
79+
/^Cannot use Foo "{}" from another module or realm./m,
9180
);
92-
expect(() => instanceOf(foo2Instance.__isFoo, foo2Instance, Foo1)).to.throw(
93-
/^Cannot use Foo "{ __isFoo: true }" from another module or realm./m,
81+
expect(() => instanceOf(true, foo2Instance, Foo1)).to.throw(
82+
/^Cannot use Foo "{}" from another module or realm./m,
9483
);
9584
});
9685
});

src/jsutils/instanceOf.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@ const isProduction =
1616
* See: https://webpack.js.org/guides/production/
1717
*/
1818
export const instanceOf: (
19-
typeBrand: true | undefined,
19+
isBranded: boolean,
2020
value: unknown,
2121
constructor: Constructor,
2222
) => boolean =
2323
/* c8 ignore next 9 */
2424
// FIXME: https://github.com/graphql/graphql-js/issues/2317
2525
isProduction
26-
? function instanceOf(typeBrand: true | undefined): boolean {
27-
return typeBrand === true;
26+
? function instanceOf(isBranded: boolean): boolean {
27+
return isBranded;
2828
}
2929
: function instanceOf(
30-
_typeBrand: true | undefined,
30+
_isBranded: boolean,
3131
value: unknown,
3232
constructor: Constructor,
3333
): boolean {

src/language/source.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ interface Location {
1414
* The `line` and `column` properties in `locationOffset` are 1-indexed.
1515
*/
1616
export class Source {
17-
readonly __isSource = true as const;
18-
1917
body: string;
2018
name: string;
2119
locationOffset: Location;
@@ -49,5 +47,9 @@ export class Source {
4947
* @internal
5048
*/
5149
export function isSource(source: unknown): source is Source {
52-
return instanceOf((source as any)?.__isSource, source, Source);
50+
return instanceOf(
51+
(source as any)?.[Symbol.toStringTag] === 'Source',
52+
source,
53+
Source,
54+
);
5355
}

0 commit comments

Comments
 (0)