assertie 0.3.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -1
- package/MIGRATION-GUIDE.md +13 -0
- package/README.md +18 -6
- package/lib/assert-helpers.d.ts +20 -0
- package/lib/assert-helpers.js +66 -0
- package/lib/index.d.ts +49 -56
- package/lib/index.js +56 -117
- package/lib/types.d.ts +29 -0
- package/lib/types.js +1 -0
- package/package.json +9 -4
- package/src/assert-helpers.ts +63 -0
- package/src/index.ts +146 -143
- package/src/types.ts +39 -0
- package/test/runtime/assert-helpers.test.ts +583 -0
- package/test/runtime/asserts.test.ts +641 -0
- package/test/runtime/main.ts +6 -0
- package/test/runtime/testing.ts +168 -0
- package/test/runtime/tsconfig.json +18 -0
- package/test/types/readonly.5+.test.ts +44 -0
- package/test/types/readonly.test.ts +238 -0
- package/test/types/run.ts +29 -0
- package/test/types/tsconfig.4.x.json +7 -0
- package/test/types/tsconfig.json +18 -0
- package/test/types/type-narrowing.5+.test.ts +32 -0
- package/test/types/type-narrowing.test.ts +654 -0
- package/tsconfig.json +1 -0
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import { group, test, mustEqual, mustBeTrue, mustBeFalse } from "./testing";
|
|
2
|
+
import {
|
|
3
|
+
getNameOfExpectedType,
|
|
4
|
+
getTypeNameOfUnknown,
|
|
5
|
+
isType,
|
|
6
|
+
} from "../../src/assert-helpers";
|
|
7
|
+
|
|
8
|
+
group("getNameOfExpectedType", () => {
|
|
9
|
+
group("primitive type strings", () => {
|
|
10
|
+
test("returns the string itself for all primitive type strings", () => {
|
|
11
|
+
mustEqual(getNameOfExpectedType("string"), "string");
|
|
12
|
+
mustEqual(getNameOfExpectedType("number"), "number");
|
|
13
|
+
mustEqual(getNameOfExpectedType("boolean"), "boolean");
|
|
14
|
+
mustEqual(getNameOfExpectedType("bigint"), "bigint");
|
|
15
|
+
mustEqual(getNameOfExpectedType("undefined"), "undefined");
|
|
16
|
+
mustEqual(getNameOfExpectedType("function"), "function");
|
|
17
|
+
mustEqual(getNameOfExpectedType("object"), "object");
|
|
18
|
+
mustEqual(getNameOfExpectedType("symbol"), "symbol");
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
group("null and undefined literals", () => {
|
|
23
|
+
test('returns "null" for null', () => {
|
|
24
|
+
mustEqual(getNameOfExpectedType(null), "null");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('returns "undefined" for undefined', () => {
|
|
28
|
+
mustEqual(getNameOfExpectedType(undefined), "undefined");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
group("constructor functions", () => {
|
|
33
|
+
test("returns class name for built-in constructors", () => {
|
|
34
|
+
mustEqual(getNameOfExpectedType(Date), "Date");
|
|
35
|
+
mustEqual(getNameOfExpectedType(Error), "Error");
|
|
36
|
+
mustEqual(getNameOfExpectedType(Array), "Array");
|
|
37
|
+
mustEqual(getNameOfExpectedType(Object), "Object");
|
|
38
|
+
mustEqual(getNameOfExpectedType(Function), "Function");
|
|
39
|
+
mustEqual(getNameOfExpectedType(RegExp), "RegExp");
|
|
40
|
+
mustEqual(getNameOfExpectedType(Map), "Map");
|
|
41
|
+
mustEqual(getNameOfExpectedType(Set), "Set");
|
|
42
|
+
mustEqual(getNameOfExpectedType(WeakMap), "WeakMap");
|
|
43
|
+
mustEqual(getNameOfExpectedType(WeakSet), "WeakSet");
|
|
44
|
+
mustEqual(getNameOfExpectedType(Promise), "Promise");
|
|
45
|
+
mustEqual(getNameOfExpectedType(ArrayBuffer), "ArrayBuffer");
|
|
46
|
+
mustEqual(getNameOfExpectedType(Uint8Array), "Uint8Array");
|
|
47
|
+
mustEqual(getNameOfExpectedType(Int32Array), "Int32Array");
|
|
48
|
+
mustEqual(getNameOfExpectedType(Float64Array), "Float64Array");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("returns class name for error subclasses", () => {
|
|
52
|
+
mustEqual(getNameOfExpectedType(TypeError), "TypeError");
|
|
53
|
+
mustEqual(getNameOfExpectedType(RangeError), "RangeError");
|
|
54
|
+
mustEqual(getNameOfExpectedType(SyntaxError), "SyntaxError");
|
|
55
|
+
mustEqual(getNameOfExpectedType(ReferenceError), "ReferenceError");
|
|
56
|
+
mustEqual(getNameOfExpectedType(URIError), "URIError");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("returns class name for named custom classes", () => {
|
|
60
|
+
class MyCustomClass {}
|
|
61
|
+
class AnotherClass {}
|
|
62
|
+
class VeryLongClassNameThatIsDescriptive {}
|
|
63
|
+
|
|
64
|
+
mustEqual(getNameOfExpectedType(MyCustomClass), "MyCustomClass");
|
|
65
|
+
mustEqual(getNameOfExpectedType(AnotherClass), "AnotherClass");
|
|
66
|
+
mustEqual(getNameOfExpectedType(VeryLongClassNameThatIsDescriptive), "VeryLongClassNameThatIsDescriptive");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("returns class name for class expressions", () => {
|
|
70
|
+
const NamedExpression = class InnerName {};
|
|
71
|
+
const AnonymousExpression = class {};
|
|
72
|
+
|
|
73
|
+
// Named class expression uses the inner name
|
|
74
|
+
mustEqual(getNameOfExpectedType(NamedExpression), "InnerName");
|
|
75
|
+
// Anonymous class expression has empty or generated name
|
|
76
|
+
mustEqual(getNameOfExpectedType(AnonymousExpression), "AnonymousExpression");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("returns class name for extended classes", () => {
|
|
80
|
+
class Parent {}
|
|
81
|
+
class Child extends Parent {}
|
|
82
|
+
class GrandChild extends Child {}
|
|
83
|
+
|
|
84
|
+
mustEqual(getNameOfExpectedType(Parent), "Parent");
|
|
85
|
+
mustEqual(getNameOfExpectedType(Child), "Child");
|
|
86
|
+
mustEqual(getNameOfExpectedType(GrandChild), "GrandChild");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("returns class name for classes extending built-ins", () => {
|
|
90
|
+
class MyArray extends Array {}
|
|
91
|
+
class MyError extends Error {}
|
|
92
|
+
class MyMap extends Map {}
|
|
93
|
+
|
|
94
|
+
mustEqual(getNameOfExpectedType(MyArray), "MyArray");
|
|
95
|
+
mustEqual(getNameOfExpectedType(MyError), "MyError");
|
|
96
|
+
mustEqual(getNameOfExpectedType(MyMap), "MyMap");
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
group("getTypeNameOfUnknown", () => {
|
|
102
|
+
group("null and undefined", () => {
|
|
103
|
+
test('returns "null" for null', () => {
|
|
104
|
+
mustEqual(getTypeNameOfUnknown(null), "null");
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('returns "undefined" for undefined', () => {
|
|
108
|
+
mustEqual(getTypeNameOfUnknown(undefined), "undefined");
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
group("primitives", () => {
|
|
113
|
+
test('returns "string" for strings', () => {
|
|
114
|
+
mustEqual(getTypeNameOfUnknown("hello"), "string");
|
|
115
|
+
mustEqual(getTypeNameOfUnknown(""), "string");
|
|
116
|
+
mustEqual(getTypeNameOfUnknown("🎉"), "string");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('returns "number" for numbers', () => {
|
|
120
|
+
mustEqual(getTypeNameOfUnknown(42), "number");
|
|
121
|
+
mustEqual(getTypeNameOfUnknown(0), "number");
|
|
122
|
+
mustEqual(getTypeNameOfUnknown(-1), "number");
|
|
123
|
+
mustEqual(getTypeNameOfUnknown(3.14), "number");
|
|
124
|
+
mustEqual(getTypeNameOfUnknown(NaN), "number");
|
|
125
|
+
mustEqual(getTypeNameOfUnknown(Infinity), "number");
|
|
126
|
+
mustEqual(getTypeNameOfUnknown(-Infinity), "number");
|
|
127
|
+
mustEqual(getTypeNameOfUnknown(-0), "number");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('returns "boolean" for booleans', () => {
|
|
131
|
+
mustEqual(getTypeNameOfUnknown(true), "boolean");
|
|
132
|
+
mustEqual(getTypeNameOfUnknown(false), "boolean");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('returns "bigint" for bigints', () => {
|
|
136
|
+
mustEqual(getTypeNameOfUnknown(0n), "bigint");
|
|
137
|
+
mustEqual(getTypeNameOfUnknown(123n), "bigint");
|
|
138
|
+
mustEqual(getTypeNameOfUnknown(-456n), "bigint");
|
|
139
|
+
mustEqual(getTypeNameOfUnknown(99999999999999999999999999999999999n), "bigint");
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('returns "symbol" for symbols', () => {
|
|
143
|
+
mustEqual(getTypeNameOfUnknown(Symbol("test")), "symbol");
|
|
144
|
+
mustEqual(getTypeNameOfUnknown(Symbol.for("global")), "symbol");
|
|
145
|
+
mustEqual(getTypeNameOfUnknown(Symbol.iterator), "symbol");
|
|
146
|
+
mustEqual(getTypeNameOfUnknown(Symbol.toStringTag), "symbol");
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
group("functions", () => {
|
|
151
|
+
test('returns correct type name for all function types', () => {
|
|
152
|
+
mustEqual(getTypeNameOfUnknown(() => {}), "Function");
|
|
153
|
+
mustEqual(getTypeNameOfUnknown(function () {}), "Function");
|
|
154
|
+
mustEqual(getTypeNameOfUnknown(function named() {}), "Function");
|
|
155
|
+
mustEqual(getTypeNameOfUnknown(async () => {}), "AsyncFunction");
|
|
156
|
+
mustEqual(getTypeNameOfUnknown(async function () {}), "AsyncFunction");
|
|
157
|
+
mustEqual(getTypeNameOfUnknown(function* () {}), "GeneratorFunction");
|
|
158
|
+
mustEqual(getTypeNameOfUnknown(async function* () {}), "AsyncGeneratorFunction");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('returns "Function" for class constructors', () => {
|
|
162
|
+
mustEqual(getTypeNameOfUnknown(class {}), "Function");
|
|
163
|
+
mustEqual(getTypeNameOfUnknown(class Named {}), "Function");
|
|
164
|
+
mustEqual(getTypeNameOfUnknown(Date), "Function");
|
|
165
|
+
mustEqual(getTypeNameOfUnknown(Array), "Function");
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('returns "Function" for bound functions', () => {
|
|
169
|
+
const fn = function () {};
|
|
170
|
+
const bound = fn.bind(null);
|
|
171
|
+
mustEqual(getTypeNameOfUnknown(bound), "Function");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('returns "Function" for Function constructor result', () => {
|
|
175
|
+
mustEqual(getTypeNameOfUnknown(new Function("return 42")), "Function");
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
group("objects - plain", () => {
|
|
180
|
+
test('returns "Object" for plain objects', () => {
|
|
181
|
+
mustEqual(getTypeNameOfUnknown({}), "Object");
|
|
182
|
+
mustEqual(getTypeNameOfUnknown({ a: 1 }), "Object");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('returns "Object" for Object.create(null)', () => {
|
|
186
|
+
mustEqual(getTypeNameOfUnknown(Object.create(null)), "Object");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
test('returns "Object" for Proxied object', () => {
|
|
190
|
+
const proxy = new Proxy({}, {});
|
|
191
|
+
mustEqual(getTypeNameOfUnknown(proxy), "Object");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
group("objects - special", () => {
|
|
197
|
+
test('returns "Array" for arrays', () => {
|
|
198
|
+
mustEqual(getTypeNameOfUnknown([]), "Array");
|
|
199
|
+
mustEqual(getTypeNameOfUnknown([1, 2, 3]), "Array");
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('returns constructor names for class instances', () => {
|
|
203
|
+
class MyClass {}
|
|
204
|
+
mustEqual(getTypeNameOfUnknown(new MyClass()), "MyClass");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('returns constructor names for built-in object instances', () => {
|
|
208
|
+
mustEqual(getTypeNameOfUnknown(new Date()), "Date");
|
|
209
|
+
mustEqual(getTypeNameOfUnknown(new Error()), "Error");
|
|
210
|
+
mustEqual(getTypeNameOfUnknown(new Map()), "Map");
|
|
211
|
+
mustEqual(getTypeNameOfUnknown(new Set()), "Set");
|
|
212
|
+
mustEqual(getTypeNameOfUnknown(new WeakMap()), "WeakMap");
|
|
213
|
+
mustEqual(getTypeNameOfUnknown(new WeakSet()), "WeakSet");
|
|
214
|
+
mustEqual(getTypeNameOfUnknown(/regex/), "RegExp");
|
|
215
|
+
mustEqual(getTypeNameOfUnknown(new ArrayBuffer(8)), "ArrayBuffer");
|
|
216
|
+
mustEqual(getTypeNameOfUnknown(new Uint8Array(8)), "Uint8Array");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test('returns "Promise" for a resolved promise', () => {
|
|
220
|
+
mustEqual(getTypeNameOfUnknown(Promise.resolve()), "Promise");
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('returns constructor names for boxed primitives', () => {
|
|
224
|
+
mustEqual(getTypeNameOfUnknown(new String("hello")), "String");
|
|
225
|
+
mustEqual(getTypeNameOfUnknown(new Number(42)), "Number");
|
|
226
|
+
mustEqual(getTypeNameOfUnknown(new Boolean(true)), "Boolean");
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
group("edge cases", () => {
|
|
231
|
+
test("frozen and sealed objects", () => {
|
|
232
|
+
mustEqual(getTypeNameOfUnknown(Object.freeze({})), "Object");
|
|
233
|
+
mustEqual(getTypeNameOfUnknown(Object.seal({})), "Object");
|
|
234
|
+
mustEqual(getTypeNameOfUnknown(Object.freeze([1, 2, 3])), "Array");
|
|
235
|
+
mustEqual(getTypeNameOfUnknown(Object.seal([1, 2, 3])), "Array");
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test("arguments object", () => {
|
|
239
|
+
function getArgs(_1: number, _2: number) {
|
|
240
|
+
// arguments is an array-like object, not an actual array
|
|
241
|
+
return arguments; // contains the function args: [_1, _2]
|
|
242
|
+
}
|
|
243
|
+
mustEqual(getTypeNameOfUnknown(getArgs(1, 2)), "Object");
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("generator and async iterator objects", () => {
|
|
247
|
+
function* gen() {
|
|
248
|
+
yield 1;
|
|
249
|
+
}
|
|
250
|
+
async function* asyncGen() {
|
|
251
|
+
yield 1;
|
|
252
|
+
}
|
|
253
|
+
mustEqual(getTypeNameOfUnknown(gen()), "Generator");
|
|
254
|
+
mustEqual(getTypeNameOfUnknown(asyncGen()), "AsyncGenerator");
|
|
255
|
+
const result = gen().next();
|
|
256
|
+
mustEqual(getTypeNameOfUnknown(result), "Object");
|
|
257
|
+
mustEqual(getTypeNameOfUnknown(result.value), "number");
|
|
258
|
+
const asyncResult = asyncGen().next();
|
|
259
|
+
mustEqual(getTypeNameOfUnknown(asyncResult), "Promise");
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
group("isType", () => {
|
|
265
|
+
group("primitive type strings - matching", () => {
|
|
266
|
+
test('returns true for "string" with strings', () => {
|
|
267
|
+
mustBeTrue(isType("hello", "string"));
|
|
268
|
+
mustBeTrue(isType("", "string"));
|
|
269
|
+
mustBeTrue(isType("🎉", "string"));
|
|
270
|
+
mustBeTrue(isType(`template ${1 + 1}`, "string"));
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test('returns true for "number" with numbers', () => {
|
|
274
|
+
mustBeTrue(isType(42, "number"));
|
|
275
|
+
mustBeTrue(isType(0, "number"));
|
|
276
|
+
mustBeTrue(isType(-1, "number"));
|
|
277
|
+
mustBeTrue(isType(3.14, "number"));
|
|
278
|
+
mustBeTrue(isType(NaN, "number"));
|
|
279
|
+
mustBeTrue(isType(Infinity, "number"));
|
|
280
|
+
mustBeTrue(isType(-Infinity, "number"));
|
|
281
|
+
mustBeTrue(isType(-0, "number"));
|
|
282
|
+
mustBeTrue(isType(Number.MAX_VALUE, "number"));
|
|
283
|
+
mustBeTrue(isType(Number.MIN_VALUE, "number"));
|
|
284
|
+
mustBeTrue(isType(Number.EPSILON, "number"));
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test('returns true for "boolean" with booleans', () => {
|
|
288
|
+
mustBeTrue(isType(true, "boolean"));
|
|
289
|
+
mustBeTrue(isType(false, "boolean"));
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('returns true for "bigint" with bigints', () => {
|
|
293
|
+
mustBeTrue(isType(0n, "bigint"));
|
|
294
|
+
mustBeTrue(isType(123n, "bigint"));
|
|
295
|
+
mustBeTrue(isType(-456n, "bigint"));
|
|
296
|
+
mustBeTrue(isType(99999999999999999999n, "bigint"));
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test('returns true for "undefined" with undefined', () => {
|
|
300
|
+
mustBeTrue(isType(undefined, "undefined"));
|
|
301
|
+
mustBeTrue(isType(undefined, undefined));
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test('returns true for "null" with null', () => {
|
|
305
|
+
mustBeTrue(isType(null, null));
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test('returns true for "function" with functions', () => {
|
|
309
|
+
mustBeTrue(isType(() => {}, "function"));
|
|
310
|
+
mustBeTrue(isType(function () {}, "function"));
|
|
311
|
+
mustBeTrue(isType(function named() {}, "function"));
|
|
312
|
+
mustBeTrue(isType(async () => {}, "function"));
|
|
313
|
+
mustBeTrue(isType(function* () {}, "function"));
|
|
314
|
+
mustBeTrue(isType(async function* () {}, "function"));
|
|
315
|
+
const bound = (function () {}).bind(null);
|
|
316
|
+
mustBeTrue(isType(bound, "function"));
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test('returns true for "function" with class constructors', () => {
|
|
320
|
+
mustBeTrue(isType(class {}, "function"));
|
|
321
|
+
mustBeTrue(isType(Date, "function"));
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test('returns true for "object" with objects', () => {
|
|
325
|
+
mustBeTrue(isType({}, "object"));
|
|
326
|
+
mustBeTrue(isType([], "object"));
|
|
327
|
+
mustBeTrue(isType(null, "object"));
|
|
328
|
+
mustBeTrue(isType(new Date(), "object"));
|
|
329
|
+
mustBeTrue(isType(/regex/, "object"));
|
|
330
|
+
mustBeTrue(isType(Promise.resolve(), "object"));
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test('returns true for "symbol" with symbols', () => {
|
|
334
|
+
mustBeTrue(isType(Symbol("test"), "symbol"));
|
|
335
|
+
mustBeTrue(isType(Symbol.for("global"), "symbol"));
|
|
336
|
+
mustBeTrue(isType(Symbol.iterator, "symbol"));
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
group("primitive type strings - mismatching", () => {
|
|
341
|
+
test('returns false for "string" with non-strings', () => {
|
|
342
|
+
mustBeFalse(isType(42, "string"));
|
|
343
|
+
mustBeFalse(isType(true, "string"));
|
|
344
|
+
mustBeFalse(isType(null, "string"));
|
|
345
|
+
mustBeFalse(isType(undefined, "string"));
|
|
346
|
+
mustBeFalse(isType({}, "string"));
|
|
347
|
+
mustBeFalse(isType(Symbol("x"), "string"));
|
|
348
|
+
mustBeFalse(isType(new String("boxed"), "string"));
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test('returns false for "number" with non-numbers', () => {
|
|
352
|
+
mustBeFalse(isType("42", "number"));
|
|
353
|
+
mustBeFalse(isType(true, "number"));
|
|
354
|
+
mustBeFalse(isType(null, "number"));
|
|
355
|
+
mustBeFalse(isType(123n, "number"));
|
|
356
|
+
mustBeFalse(isType(new Number(42), "number"));
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
test('returns false for "boolean" with non-booleans', () => {
|
|
360
|
+
mustBeFalse(isType(0, "boolean"));
|
|
361
|
+
mustBeFalse(isType(1, "boolean"));
|
|
362
|
+
mustBeFalse(isType("true", "boolean"));
|
|
363
|
+
mustBeFalse(isType(null, "boolean"));
|
|
364
|
+
mustBeFalse(isType(new Boolean(true), "boolean"));
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
test('returns false for "bigint" with non-bigints', () => {
|
|
368
|
+
mustBeFalse(isType(123, "bigint"));
|
|
369
|
+
mustBeFalse(isType("123", "bigint"));
|
|
370
|
+
mustBeFalse(isType(Object(123n), "bigint"));
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
test('returns false for "undefined" with non-undefined', () => {
|
|
374
|
+
mustBeFalse(isType(null, "undefined"));
|
|
375
|
+
mustBeFalse(isType("", "undefined"));
|
|
376
|
+
mustBeFalse(isType(0, "undefined"));
|
|
377
|
+
mustBeFalse(isType(false, "undefined"));
|
|
378
|
+
mustBeFalse(isType({}, "undefined"));
|
|
379
|
+
mustBeFalse(isType(null, undefined));
|
|
380
|
+
mustBeFalse(isType("", undefined));
|
|
381
|
+
mustBeFalse(isType(0, undefined));
|
|
382
|
+
mustBeFalse(isType(false, undefined));
|
|
383
|
+
mustBeFalse(isType({}, undefined));
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
test("returns false for null with non-null", () => {
|
|
387
|
+
mustBeFalse(isType(undefined, null));
|
|
388
|
+
mustBeFalse(isType("", null));
|
|
389
|
+
mustBeFalse(isType(0, null));
|
|
390
|
+
mustBeFalse(isType(false, null));
|
|
391
|
+
mustBeFalse(isType({}, null));
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
test('returns false for "function" with non-functions', () => {
|
|
395
|
+
mustBeFalse(isType("", "function"));
|
|
396
|
+
mustBeFalse(isType({}, "function"));
|
|
397
|
+
mustBeFalse(isType([], "function"));
|
|
398
|
+
mustBeFalse(isType(new Date(), "function"));
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test('returns false for "object" with non-objects', () => {
|
|
402
|
+
mustBeFalse(isType("string", "object"));
|
|
403
|
+
mustBeFalse(isType(42, "object"));
|
|
404
|
+
mustBeFalse(isType(42n, "object"));
|
|
405
|
+
mustBeFalse(isType(true, "object"));
|
|
406
|
+
mustBeFalse(isType(undefined, "object"));
|
|
407
|
+
mustBeFalse(isType(() => {}, "object"));
|
|
408
|
+
mustBeFalse(isType(Symbol("x"), "object"));
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test('returns false for "symbol" with non-symbols', () => {
|
|
412
|
+
mustBeFalse(isType("symbol", "symbol"));
|
|
413
|
+
mustBeFalse(isType({}, "symbol"));
|
|
414
|
+
mustBeFalse(isType(Object(Symbol("boxed")), "symbol"));
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
group("constructors - instanceof checks", () => {
|
|
419
|
+
test("returns true for instances of built-in classes", () => {
|
|
420
|
+
mustBeTrue(isType(new Date(), Date));
|
|
421
|
+
mustBeTrue(isType(new Error(), Error));
|
|
422
|
+
mustBeTrue(isType(new TypeError(), TypeError));
|
|
423
|
+
mustBeTrue(isType([], Array));
|
|
424
|
+
mustBeTrue(isType({}, Object));
|
|
425
|
+
mustBeTrue(isType(/regex/, RegExp));
|
|
426
|
+
mustBeTrue(isType(new Map(), Map));
|
|
427
|
+
mustBeTrue(isType(new Set(), Set));
|
|
428
|
+
mustBeTrue(isType(new WeakMap(), WeakMap));
|
|
429
|
+
mustBeTrue(isType(new WeakSet(), WeakSet));
|
|
430
|
+
mustBeTrue(isType(Promise.resolve(), Promise));
|
|
431
|
+
mustBeTrue(isType(new ArrayBuffer(8), ArrayBuffer));
|
|
432
|
+
mustBeTrue(isType(new Uint8Array(8), Uint8Array));
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
test("returns true for instances of custom classes", () => {
|
|
436
|
+
class MyClass {}
|
|
437
|
+
mustBeTrue(isType(new MyClass(), MyClass));
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test("returns true for all function types with Function", () => {
|
|
441
|
+
mustBeTrue(isType(() => {}, Function));
|
|
442
|
+
mustBeTrue(isType(async () => {}, Function));
|
|
443
|
+
mustBeTrue(isType(function* () {}, Function));
|
|
444
|
+
mustBeTrue(isType(async function* () {}, Function));
|
|
445
|
+
mustBeTrue(isType(class {}, Function));
|
|
446
|
+
const bound = (function () {}).bind(null);
|
|
447
|
+
mustBeTrue(isType(bound, Function));
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test("returns false for non-instances", () => {
|
|
451
|
+
mustBeFalse(isType({}, Date));
|
|
452
|
+
mustBeFalse(isType({}, Array));
|
|
453
|
+
mustBeFalse(isType([], Map));
|
|
454
|
+
mustBeFalse(isType(new Date(), Error));
|
|
455
|
+
|
|
456
|
+
class MyClass {}
|
|
457
|
+
mustBeFalse(isType({}, MyClass));
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
test("returns true when item IS the constructor itself", () => {
|
|
461
|
+
mustBeTrue(isType(Date, Date));
|
|
462
|
+
mustBeTrue(isType(Array, Array));
|
|
463
|
+
|
|
464
|
+
class MyClass {}
|
|
465
|
+
mustBeTrue(isType(MyClass, MyClass));
|
|
466
|
+
});
|
|
467
|
+
|
|
468
|
+
test("inheritance chain works correctly", () => {
|
|
469
|
+
class A {}
|
|
470
|
+
class B extends A {}
|
|
471
|
+
class C extends B {}
|
|
472
|
+
|
|
473
|
+
const c = new C();
|
|
474
|
+
mustBeTrue(isType(c, C));
|
|
475
|
+
mustBeTrue(isType(c, B));
|
|
476
|
+
mustBeTrue(isType(c, A));
|
|
477
|
+
mustBeTrue(isType(c, Object));
|
|
478
|
+
|
|
479
|
+
const b = new B();
|
|
480
|
+
mustBeTrue(isType(b, B));
|
|
481
|
+
mustBeTrue(isType(b, A));
|
|
482
|
+
mustBeFalse(isType(b, C));
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
test("extended built-in classes", () => {
|
|
486
|
+
class MyArray extends Array {}
|
|
487
|
+
class MyError extends Error {}
|
|
488
|
+
class MyMap extends Map {}
|
|
489
|
+
|
|
490
|
+
const arr = new MyArray();
|
|
491
|
+
const err = new MyError();
|
|
492
|
+
const map = new MyMap();
|
|
493
|
+
|
|
494
|
+
mustBeTrue(isType(arr, MyArray));
|
|
495
|
+
mustBeTrue(isType(arr, Array));
|
|
496
|
+
mustBeTrue(isType(err, MyError));
|
|
497
|
+
mustBeTrue(isType(err, Error));
|
|
498
|
+
mustBeTrue(isType(map, MyMap));
|
|
499
|
+
mustBeTrue(isType(map, Map));
|
|
500
|
+
});
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
group("edge cases", () => {
|
|
504
|
+
test("class alias is identical", () => {
|
|
505
|
+
class MyClass {}
|
|
506
|
+
const instance = new MyClass();
|
|
507
|
+
|
|
508
|
+
const OtherClass = MyClass;
|
|
509
|
+
const otherInstance = new OtherClass();
|
|
510
|
+
|
|
511
|
+
mustBeTrue(isType(instance, MyClass));
|
|
512
|
+
mustBeTrue(isType(instance, OtherClass));
|
|
513
|
+
mustBeTrue(isType(otherInstance, MyClass));
|
|
514
|
+
mustBeTrue(isType(otherInstance, OtherClass));
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
test("Symbol.hasInstance override", () => {
|
|
518
|
+
class AlwaysTrue {
|
|
519
|
+
static [Symbol.hasInstance]() {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
class AlwaysFalse {
|
|
524
|
+
static [Symbol.hasInstance]() {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// isType uses instanceof which respects Symbol.hasInstance
|
|
530
|
+
mustBeTrue(isType("not an instance", AlwaysTrue));
|
|
531
|
+
mustBeFalse(isType(new AlwaysFalse(), AlwaysFalse));
|
|
532
|
+
mustBeFalse(isType("other", AlwaysFalse));
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
group("Proxy objects", () => {
|
|
536
|
+
test("Proxy of object is still object", () => {
|
|
537
|
+
const proxy = new Proxy({}, {});
|
|
538
|
+
mustBeTrue(isType(proxy, "object"));
|
|
539
|
+
mustBeTrue(isType(proxy, Object));
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
test("Proxy of function is still function", () => {
|
|
543
|
+
const proxy = new Proxy(() => {}, {});
|
|
544
|
+
mustBeTrue(isType(proxy, "function"));
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
test("Proxy of class instance maintains instanceof", () => {
|
|
548
|
+
class MyClass {}
|
|
549
|
+
const proxy = new Proxy(new MyClass(), {});
|
|
550
|
+
mustBeTrue(isType(proxy, MyClass));
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
test("Proxy of array is instanceof Array", () => {
|
|
554
|
+
const proxy = new Proxy([1, 2, 3], {});
|
|
555
|
+
mustBeTrue(isType(proxy, Array));
|
|
556
|
+
});
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
test("Object.create(null) is typeof object but not instanceof Object", () => {
|
|
560
|
+
const nullProto = Object.create(null);
|
|
561
|
+
mustBeTrue(isType(nullProto, "object"));
|
|
562
|
+
mustBeFalse(isType(nullProto, Object));
|
|
563
|
+
mustBeFalse(isType(nullProto, null));
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
test("TypedArrays are NOT instanceof Array", () => {
|
|
567
|
+
mustBeFalse(isType(new Uint8Array(8), Array));
|
|
568
|
+
mustBeTrue(isType(new Int32Array(8), Int32Array));
|
|
569
|
+
mustBeTrue(isType(new Float64Array(8), Float64Array));
|
|
570
|
+
mustBeTrue(isType(new ArrayBuffer(8), ArrayBuffer));
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
test("arguments object is object but not Array", () => {
|
|
574
|
+
function getArgs(_1: number, _2: number) {
|
|
575
|
+
// arguments is an array-like object, not an actual array
|
|
576
|
+
return arguments; // contains the function args: [_1, _2]
|
|
577
|
+
}
|
|
578
|
+
const args = getArgs(1, 2);
|
|
579
|
+
mustBeTrue(isType(args, Object));
|
|
580
|
+
mustBeFalse(isType(args, Array));
|
|
581
|
+
});
|
|
582
|
+
});
|
|
583
|
+
});
|