Skip to content

Commit c2632f3

Browse files
committed
refactor: Rationalize isInstance methods
1 parent 5e87af2 commit c2632f3

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed

packages/json-rpc-engine/src/v2/MiddlewareContext.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,10 @@ describe('MiddlewareContext', () => {
7575
);
7676
});
7777

78-
it('detects instances of MiddlewareContext', () => {
78+
it('identifies instances of MiddlewareContext via isInstance', () => {
7979
const context = new MiddlewareContext();
80-
expect(MiddlewareContext.isInstance(context)).toBe(true);
81-
});
8280

83-
it('detects sub-classes of MiddlewareContext', () => {
84-
class SubContext extends MiddlewareContext {}
85-
const context = new SubContext();
8681
expect(MiddlewareContext.isInstance(context)).toBe(true);
82+
expect(MiddlewareContext.isInstance({ foo: 'bar' })).toBe(false);
8783
});
8884
});

packages/json-rpc-engine/src/v2/MiddlewareContext.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { isObject } from '@metamask/utils';
2-
3-
import type { UnionToIntersection } from './utils';
1+
import { isInstance, type UnionToIntersection } from './utils';
42

53
const MiddlewareContextSymbol = Symbol.for('json-rpc-engine#MiddlewareContext');
64

@@ -41,11 +39,7 @@ export class MiddlewareContext<
4139
* @returns Whether the value is a {@link MiddlewareContext} instance.
4240
*/
4341
static isInstance(value: unknown): value is MiddlewareContext {
44-
return (
45-
isObject(value) &&
46-
MiddlewareContextSymbol in value &&
47-
value[MiddlewareContextSymbol] === true
48-
);
42+
return isInstance(value, MiddlewareContextSymbol);
4943
}
5044

5145
constructor(

packages/json-rpc-engine/src/v2/utils.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
isNotification,
44
stringify,
55
JsonRpcEngineError,
6+
isInstance,
67
} from './utils';
78

89
const jsonrpc = '2.0' as const;
@@ -54,6 +55,30 @@ describe('utils', () => {
5455
});
5556
});
5657

58+
describe('isInstance', () => {
59+
const TestClassSymbol = Symbol('TestClass');
60+
61+
class TestClass {
62+
private readonly [TestClassSymbol] = true;
63+
}
64+
65+
it('identifies class instances via the symbol property', () => {
66+
const value = new TestClass();
67+
expect(isInstance(value, TestClassSymbol)).toBe(true);
68+
});
69+
70+
it('identifies plain objects via the symbol property', () => {
71+
const value = { [TestClassSymbol]: true };
72+
expect(isInstance(value, TestClassSymbol)).toBe(true);
73+
});
74+
75+
it('identifies sub-classes of the class via the symbol property', () => {
76+
class SubClass extends TestClass {}
77+
const value = new SubClass();
78+
expect(isInstance(value, TestClassSymbol)).toBe(true);
79+
});
80+
});
81+
5782
describe('JsonRpcEngineError', () => {
5883
it('creates an error with the correct name', () => {
5984
const error = new JsonRpcEngineError('test');
@@ -62,8 +87,9 @@ describe('utils', () => {
6287
expect(error.message).toBe('test');
6388
});
6489

65-
it('isInstance checks if a value is a JsonRpcEngineError instance', () => {
90+
it('identifies JsonRpcEngineError instances via isInstance', () => {
6691
const error = new JsonRpcEngineError('test');
92+
6793
expect(JsonRpcEngineError.isInstance(error)).toBe(true);
6894
expect(JsonRpcEngineError.isInstance(new Error('test'))).toBe(false);
6995
});

packages/json-rpc-engine/src/v2/utils.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
hasProperty,
3+
isObject,
34
type JsonRpcNotification,
45
type JsonRpcParams,
56
type JsonRpcRequest,
@@ -48,6 +49,19 @@ export function stringify(value: unknown): string {
4849
return JSON.stringify(value, null, 2);
4950
}
5051

52+
/**
53+
* The implementation of static `isInstance` methods for classes that have them.
54+
*
55+
* @param value - The value to check.
56+
* @param symbol - The symbol property to check for.
57+
* @returns Whether the value has `{ [symbol]: true }` in its prototype chain.
58+
*/
59+
export const isInstance = (
60+
value: unknown,
61+
symbol: symbol,
62+
): value is { [key: symbol]: true } =>
63+
isObject(value) && symbol in value && value[symbol] === true;
64+
5165
const JsonRpcEngineErrorSymbol = Symbol.for(
5266
'json-rpc-engine#JsonRpcEngineError',
5367
);
@@ -67,12 +81,7 @@ export class JsonRpcEngineError extends Error {
6781
* @param value - The value to check.
6882
* @returns Whether the value is a {@link JsonRpcEngineError} instance.
6983
*/
70-
static isInstance<Value extends Error>(
71-
value: Value,
72-
): value is Value & JsonRpcEngineError {
73-
return (
74-
JsonRpcEngineErrorSymbol in value &&
75-
value[JsonRpcEngineErrorSymbol] === true
76-
);
84+
static isInstance(value: unknown): value is JsonRpcEngineError {
85+
return isInstance(value, JsonRpcEngineErrorSymbol);
7786
}
7887
}

0 commit comments

Comments
 (0)