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/lib/index.js CHANGED
@@ -1,319 +1,258 @@
1
- function getNameOfExpectedType(expectedType) {
2
- if (expectedType === null)
3
- return "null";
4
- if (expectedType === undefined)
5
- return "undefined";
6
- if (typeof expectedType === "string")
7
- return expectedType;
8
- return expectedType.name;
9
- }
10
- function getTypeNameOfUnknown(item) {
11
- if (item === null)
12
- return "null";
13
- if (item === undefined)
14
- return "undefined";
15
- try {
16
- if (item instanceof item.constructor && item.constructor.name !== "Function") {
17
- // I'd like function to match the primitive name "function"
18
- // because that's how the asserts are written.
19
- return item.constructor.name;
20
- }
21
- }
22
- finally {
23
- return typeof item;
24
- }
25
- }
26
- function isType(item, expectedType) {
27
- if (typeof item === expectedType)
28
- return true;
29
- const reducedExpectedType = expectedType;
30
- if (item === reducedExpectedType)
31
- return true;
32
- const remainingOption = expectedType;
33
- if (item instanceof remainingOption)
34
- return true;
35
- return false;
36
- }
37
- class AssertionError extends Error {
1
+ import { getNameOfExpectedType, getTypeNameOfUnknown, isType } from "./assert-helpers";
2
+ /**
3
+ * Error thrown by all assertie assertions when they fail.
4
+ */
5
+ export class AssertieError extends Error {
38
6
  constructor(msg) {
39
7
  super(`Assertion failed: ${msg}`);
40
- this.name = AssertionError.name;
8
+ this.name = AssertieError.name;
41
9
  }
42
10
  }
43
11
  /**
44
12
  * Asserts that the provided boolean is true.
45
13
  * @param {boolean} hasToBeTrue - The boolean to assert.
46
14
  * @param {string} msg - The message of the Error if the assertion fails.
47
- * @throws {AssertionError} if the assertion fails.
15
+ * @throws {AssertieError} if the assertion fails.
48
16
  */
49
17
  export function assert(hasToBeTrue, msg = "No specific message provided.") {
50
18
  if (!import.meta.env.DEV)
51
19
  return;
52
20
  if (!hasToBeTrue)
53
- throw new AssertionError(msg);
21
+ throw new AssertieError(msg);
54
22
  }
55
23
  /**
56
- * Asserts that the provided object is of the expectedType.
57
- * @param {unknown} item - The object which ought to be of the expectedType.
58
- * @param {AllJSTypes} expectedType - The expected type of the object. JS primitive types, null, undefined, and constructable types are supported. JS primitive types are passed as the string they return from typeof, e.g., "number".
59
- * @throws {AssertionError} if the type isn't as expected.
24
+ * Asserts that the provided item is of the expectedType.
25
+ * @param {unknown} item - The item which ought to be of the expectedType.
26
+ * @param {AllJSTypes} expectedType - The expected type of the item. JS primitive types, null, undefined, and constructable types are supported. JS primitive types are passed as the string they return from typeof, e.g., "number".
27
+ * @throws {AssertieError} if the type isn't as expected.
60
28
  */
61
29
  export function assertType(item, expectedType) {
62
30
  if (!import.meta.env.DEV)
63
31
  return;
64
32
  if (!isType(item, expectedType))
65
- throw new AssertionError(`Provided object was not of type ${getNameOfExpectedType(expectedType)}. Was: ${getTypeNameOfUnknown(item)}, value: ${item}`);
33
+ throw new AssertieError(`Provided object was not of type ${getNameOfExpectedType(expectedType)}. Was: ${getTypeNameOfUnknown(item)}, value: ${item}`);
66
34
  }
67
- /**
68
- * Asserts that all elements of the provided array are of the expected type. It ensures that the array is not sparse (even when the expectedType is undefined).
69
- * @param {unknown[]} arr - The array which ought to be an array of the expectedType, i.e. expectedType: "number" => arr: number[]
70
- * @param {AllJSTypes} expectedType - The expected type of individual items. JS primitive types, null, undefined, and constructable types are supported.
71
- * @throws {AssertionError} if the type isn't as expected.
72
- */
73
35
  export function assertArrayType(arr, expectedType) {
74
36
  if (!import.meta.env.DEV)
75
37
  return;
76
38
  for (let i = 0; i < arr.length; i++) {
77
39
  if (!(i in arr))
78
- throw new AssertionError(`Array to assert type of was sparse with a missing item at index ${i}`);
40
+ throw new AssertieError(`Array to assert type of was sparse with a missing item at index ${i}`);
79
41
  const item = arr[i];
80
42
  if (!isType(item, expectedType))
81
- throw new AssertionError(`Provided array had item at index ${i} not of type ${getNameOfExpectedType(expectedType)}. Was: ${getTypeNameOfUnknown(item)}, value: ${item}`);
43
+ throw new AssertieError(`Provided array had item at index ${i} not of type ${getNameOfExpectedType(expectedType)}. Was: ${getTypeNameOfUnknown(item)}, value: ${item}`);
82
44
  }
83
45
  }
84
- /**
85
- * Asserts that the array or tuple has the expected types at each index.
86
- * @param {unknown[] | [unknown, ...]} arrayOrTuple - The tuple which ought to be an array of the length and types.
87
- * @param {[AllJSTypes, ...]} expectedTypes - A tuple of expected types of individual items, e.g., expectedTypes = ["number", "string", Date] => arrayOrTuple: [number, string, Date]. The individual entries can be JS primitive types, null, undefined, and constructors.
88
- * @throws {AssertionError} if the type of any element of the tuple isn't as expected.
89
- */
90
46
  export function assertTupleTypes(arrayOrTuple, expectedTypes) {
91
47
  if (!import.meta.env.DEV)
92
48
  return;
93
49
  if (arrayOrTuple.length !== expectedTypes.length) {
94
- throw new AssertionError(`Provided tuple length mismatch: expected ${expectedTypes.length}, but got ${arrayOrTuple.length}`);
50
+ throw new AssertieError(`Provided tuple length mismatch: expected ${expectedTypes.length}, but got ${arrayOrTuple.length}`);
95
51
  }
96
52
  for (let i = 0; i < expectedTypes.length; i++) {
97
53
  if (!(i in arrayOrTuple))
98
- throw new AssertionError(`Provided tuple was sparse with a missing item at required index ${i}`);
54
+ throw new AssertieError(`Provided tuple was sparse with a missing item at required index ${i}`);
99
55
  const item = arrayOrTuple[i];
100
56
  if (!isType(item, expectedTypes[i])) {
101
- throw new AssertionError(`Provided tuple had item at index ${i} not of type ${getNameOfExpectedType(expectedTypes[i])}. Was: ${getTypeNameOfUnknown(item)}, value: ${item}`);
57
+ throw new AssertieError(`Provided tuple had item at index ${i} not of type ${getNameOfExpectedType(expectedTypes[i])}. Was: ${getTypeNameOfUnknown(item)}, value: ${item}`);
102
58
  }
103
59
  }
104
60
  }
105
61
  /**
106
62
  * Asserts that the provided item is of type string.
107
63
  * @param {unknown} item - The item which ought to be of type string.
108
- * @throws {AssertionError} if the type isn't string.
64
+ * @throws {AssertieError} if the type isn't string.
109
65
  */
110
66
  export function assertTypeOfString(item) {
111
67
  if (!import.meta.env.DEV)
112
68
  return;
113
69
  if (typeof item !== "string")
114
- throw new AssertionError(`Provided item was not of type string. Was: ${getTypeNameOfUnknown(item)}`);
70
+ throw new AssertieError(`Provided item was not of type string. Was: ${getTypeNameOfUnknown(item)}`);
115
71
  }
116
72
  /**
117
73
  * Asserts that the provided item is of type number.
118
74
  * @param {unknown} item - The item which ought to be of type number.
119
- * @throws {AssertionError} if the type isn't number.
75
+ * @throws {AssertieError} if the type isn't number.
120
76
  */
121
77
  export function assertTypeOfNumber(item) {
122
78
  if (!import.meta.env.DEV)
123
79
  return;
124
80
  if (typeof item !== "number")
125
- throw new AssertionError(`Provided item was not of type number. Was: ${getTypeNameOfUnknown(item)}`);
81
+ throw new AssertieError(`Provided item was not of type number. Was: ${getTypeNameOfUnknown(item)}`);
126
82
  }
127
83
  /**
128
84
  * Asserts that the provided item is of type boolean.
129
85
  * @param {unknown} item - The item which ought to be of type boolean.
130
- * @throws {AssertionError} if the type isn't boolean.
86
+ * @throws {AssertieError} if the type isn't boolean.
131
87
  */
132
88
  export function assertTypeOfBoolean(item) {
133
89
  if (!import.meta.env.DEV)
134
90
  return;
135
91
  if (typeof item !== "boolean")
136
- throw new AssertionError(`Provided item was not of type boolean. Was: ${getTypeNameOfUnknown(item)}`);
92
+ throw new AssertieError(`Provided item was not of type boolean. Was: ${getTypeNameOfUnknown(item)}`);
137
93
  }
138
94
  /**
139
95
  * Asserts that the provided item is of type bigint.
140
96
  * @param {unknown} item - The item which ought to be of type bigint.
141
- * @throws {AssertionError} if the type isn't bigint.
97
+ * @throws {AssertieError} if the type isn't bigint.
142
98
  */
143
99
  export function assertTypeOfBigint(item) {
144
100
  if (!import.meta.env.DEV)
145
101
  return;
146
102
  if (typeof item !== "bigint")
147
- throw new AssertionError(`Provided item was not of type bigint. Was: ${getTypeNameOfUnknown(item)}`);
103
+ throw new AssertieError(`Provided item was not of type bigint. Was: ${getTypeNameOfUnknown(item)}`);
148
104
  }
149
105
  /**
150
106
  * Asserts that the provided item is of type undefined.
151
107
  * @param {unknown} item - The item which ought to be of type undefined.
152
- * @throws {AssertionError} if the type isn't undefined.
108
+ * @throws {AssertieError} if the type isn't undefined.
153
109
  */
154
110
  export function assertTypeOfUndefined(item) {
155
111
  if (!import.meta.env.DEV)
156
112
  return;
157
113
  if (typeof item !== "undefined")
158
- throw new AssertionError(`Provided item was not of type undefined. Was: ${getTypeNameOfUnknown(item)}`);
114
+ throw new AssertieError(`Provided item was not of type undefined. Was: ${getTypeNameOfUnknown(item)}`);
159
115
  }
160
116
  /**
161
117
  * Asserts that the provided item is of type function.
162
118
  * @param {unknown} item - The item which ought to be of type function.
163
- * @throws {AssertionError} if the type isn't function.
119
+ * @throws {AssertieError} if the type isn't function.
164
120
  */
165
121
  export function assertTypeOfFunction(item) {
166
122
  if (!import.meta.env.DEV)
167
123
  return;
168
124
  if (typeof item !== "function")
169
- throw new AssertionError(`Provided item was not of type function. Was: ${getTypeNameOfUnknown(item)}`);
125
+ throw new AssertieError(`Provided item was not of type function. Was: ${getTypeNameOfUnknown(item)}`);
170
126
  }
171
127
  /**
172
128
  * Asserts that the provided item is of type object.
173
129
  * @param {unknown} item - The item which ought to be of type object.
174
- * @throws {AssertionError} if the type isn't object.
130
+ * @throws {AssertieError} if the type isn't object.
175
131
  */
176
132
  export function assertTypeOfObject(item) {
177
133
  if (!import.meta.env.DEV)
178
134
  return;
179
135
  if (typeof item !== "object")
180
- throw new AssertionError(`Provided item was not of type object. Was: ${getTypeNameOfUnknown(item)}`);
136
+ throw new AssertieError(`Provided item was not of type object. Was: ${getTypeNameOfUnknown(item)}`);
181
137
  }
182
138
  /**
183
139
  * Asserts that the provided item is of type symbol.
184
140
  * @param {unknown} item - The item which ought to be of type symbol.
185
- * @throws {AssertionError} if the type isn't symbol.
141
+ * @throws {AssertieError} if the type isn't symbol.
186
142
  */
187
143
  export function assertTypeOfSymbol(item) {
188
144
  if (!import.meta.env.DEV)
189
145
  return;
190
146
  if (typeof item !== "symbol")
191
- throw new AssertionError(`Provided item was not of type symbol. Was: ${getTypeNameOfUnknown(item)}`);
147
+ throw new AssertieError(`Provided item was not of type symbol. Was: ${getTypeNameOfUnknown(item)}`);
192
148
  }
193
149
  /**
194
150
  * Asserts that the provided item is null.
195
151
  * @param {unknown} item - The item which ought to be null.
196
- * @throws {AssertionError} if the value isn't null.
152
+ * @throws {AssertieError} if the value isn't null.
197
153
  */
198
154
  export function assertNull(item) {
199
155
  if (!import.meta.env.DEV)
200
156
  return;
201
157
  if (item !== null)
202
- throw new AssertionError(`Provided item was not null. Was type: ${getTypeNameOfUnknown(item)}, value: ${item}`);
158
+ throw new AssertieError(`Provided item was not null. Was type: ${getTypeNameOfUnknown(item)}, value: ${item}`);
203
159
  }
204
160
  /**
205
161
  * Asserts that the provided item is an instance of the provided constructor.
206
162
  * @param {unknown} item - The item which ought to be an instance of the constructor.
207
163
  * @param {Constructor<T>} constructor - Anything that can be after an instanceof operator.
208
- * @throws {AssertionError} if item instanceof constructor is false.
164
+ * @throws {AssertieError} if item instanceof constructor is false.
209
165
  */
210
166
  export function assertInstanceOf(item, constructor) {
211
167
  if (!import.meta.env.DEV)
212
168
  return;
213
169
  if (!(item instanceof constructor))
214
- throw new AssertionError(`Provided item was not of type ${constructor.name} but was type: ${getTypeNameOfUnknown(item)}, value: ${item}`);
170
+ throw new AssertieError(`Provided item was not of type ${constructor.name} but was type: ${getTypeNameOfUnknown(item)}, value: ${item}`);
215
171
  }
216
- /**
217
- * Asserts that the provided array is a tuple of exactly the expected length.
218
- * @param {unknown[]} arr - The array which ought to be a tuple.
219
- * @param {number} expectedLength - The exact expected length of the tuple.
220
- * @throws {AssertionError} if the array isn't of the expected length or is sparse.
221
- */
222
172
  export function assertIsTuple(arr, expectedLength) {
223
173
  if (!import.meta.env.DEV)
224
174
  return;
225
175
  if (arr.length !== expectedLength) {
226
- throw new AssertionError(`Provided array is not a tuple of expected length ${expectedLength}. It has length ${arr.length}.`);
176
+ throw new AssertieError(`Provided array is not a tuple of expected length ${expectedLength}. It has length ${arr.length}.`);
227
177
  }
228
178
  for (let i = 0; i < expectedLength; i++) {
229
179
  if (!(i in arr))
230
- throw new AssertionError(`Provided tuple is sparse and therefore not a tuple. Index ${i} is missing.`);
180
+ throw new AssertieError(`Provided tuple is sparse and therefore not a tuple. Index ${i} is missing.`);
231
181
  }
232
182
  }
233
183
  /**
234
184
  * Used to assert that code can never be reached. Pass a value which has already been checked for all types that should be possible. If the range of possible values increases, TypeScript will throw an error at compile time because the value won't be of type never.
235
185
  * @param {never} item - An exhausted value, of which all cases are accounted for in other branches of the code, such as at the end of a switch statement.
236
186
  * @param {string} msg - Override the default error message. Even if you do, the error message will include the value and type of item.
237
- * @throws {AssertionError} if at runtime the function call was reached. This should only happen if TypeScript types are inaccurate somewhere.
187
+ * @throws {AssertieError} if at runtime the function call was reached. This should only happen if TypeScript types are inaccurate somewhere.
238
188
  */
239
189
  export function assertUnreachable(item, msg = "Unreachable code of type never was reached. TypeScript types are inaccurate somewhere.") {
240
190
  if (!import.meta.env.DEV)
241
191
  return;
242
- throw new AssertionError(msg +
243
- `\nValue of type never was actually of type: ${getTypeNameOfUnknown(item)}, value: ${item}`);
192
+ throw new AssertieError(msg + `\nValue of type never was actually of type: ${getTypeNameOfUnknown(item)}, value: ${item}`);
244
193
  }
245
194
  /**
246
195
  * Asserts that the provided item is neither null nor undefined.
247
196
  * @param {unknown} item - The item which ought to be non-null.
248
- * @throws {AssertionError} if the item is null or undefined.
197
+ * @throws {AssertieError} if the item is null or undefined.
249
198
  */
250
199
  export function assertNonNullable(item) {
251
200
  if (!import.meta.env.DEV)
252
201
  return;
253
202
  if (item === undefined || item === null)
254
- throw new AssertionError(`Provided item should've been non-null but was: ${item}`);
203
+ throw new AssertieError(`Provided item should've been non-null but was: ${item}`);
255
204
  }
256
205
  /**
257
206
  * Asserts that the provided object has non-null values for the properties passed as keys in the propKeys array.
258
207
  * @param {object} obj - The object which ought to have the properties.
259
208
  * @param {NullableKeys<T>} propKeys - An array of the stringified keys of the properties which ought to be non-null in the object.
260
- * @throws {AssertionError} if any of the properties was null, undefined, or not present in the object.
209
+ * @throws {AssertieError} if any of the properties was null, undefined, or not present in the object.
261
210
  */
262
211
  export function assertPropsNonNullable(obj, propKeys) {
263
212
  if (!import.meta.env.DEV)
264
213
  return;
265
214
  for (const propKey of propKeys) {
266
215
  if (!(propKey in obj))
267
- throw new AssertionError(`Provided object prop ${String(propKey)} should've been non-null but was not present at all.`);
216
+ throw new AssertieError(`Provided object prop ${String(propKey)} should've been non-null but was not present at all.`);
268
217
  if (obj[propKey] === null || obj[propKey] === undefined)
269
- throw new AssertionError(`Provided object prop ${String(propKey)} should've been non-null but was: ${obj[propKey]}`);
218
+ throw new AssertieError(`Provided object prop ${String(propKey)} should've been non-null but was: ${obj[propKey]}`);
270
219
  }
271
220
  }
272
- /**
273
- * Asserts that all elements of the provided array are neither null nor undefined, or not present.
274
- * @param {unknown[]} arr - The array which ought to be non-sparse, and have only non-null elements.
275
- * @throws {AssertionError} if any of the elements was null, undefined, or not present in the array.
276
- */
277
221
  export function assertArrayNonNullable(arr) {
278
222
  if (!import.meta.env.DEV)
279
223
  return;
280
224
  for (let i = 0; i < arr.length; i++) {
281
225
  if (!(i in arr))
282
- throw new AssertionError(`Provided array should've been non-null but was sparse with a missing item at index ${i}`);
226
+ throw new AssertieError(`Provided array should've been non-null but was sparse with a missing item at index ${i}`);
283
227
  const item = arr[i];
284
228
  if (item === null)
285
- throw new AssertionError(`Provided array should've been non-null but had an item with value null at index ${i}`);
229
+ throw new AssertieError(`Provided array should've been non-null but had an item with value null at index ${i}`);
286
230
  if (item === undefined)
287
- throw new AssertionError(`Provided array should've been non-null but had an undefined item at index ${i}`);
231
+ throw new AssertieError(`Provided array should've been non-null but had an undefined item at index ${i}`);
288
232
  }
289
233
  }
290
- /**
291
- * Asserts that the provided tuple has non-null values for all elements. This function does not take a length. So if you want to assert that the typescript tuple type is of the correct length, call @see assertIsTuple first.
292
- * @param {[unknown, ...]} tuple - The tuple which ought to have only non-null values.
293
- * @throws {AssertionError} if any of the elements was null, undefined, or an index not present in the tuple.
294
- */
295
234
  export function assertTupleNonNullable(tuple) {
296
235
  if (!import.meta.env.DEV)
297
236
  return;
298
237
  for (let i = 0; i < tuple.length; i++) {
299
238
  if (!(i in tuple))
300
- throw new AssertionError(`Provided tuple should've been non-null but is sparse. Index ${i} is missing.`);
239
+ throw new AssertieError(`Provided tuple should've been non-null but is sparse. Index ${i} is missing.`);
301
240
  if (tuple[i] === null)
302
- throw new AssertionError(`Provided tuple should've been non-null but had an item with value null at index ${i}`);
241
+ throw new AssertieError(`Provided tuple should've been non-null but had an item with value null at index ${i}`);
303
242
  if (tuple[i] === undefined)
304
- throw new AssertionError(`Provided tuple should've been non-null but had an undefined item at index ${i}`);
243
+ throw new AssertieError(`Provided tuple should've been non-null but had an undefined item at index ${i}`);
305
244
  }
306
245
  }
307
246
  /**
308
247
  * Asserts that the provided item is a finite number. Use to prevent NaN propagation.
309
248
  * @param {unknown} item - The item which ought to be a finite number.
310
- * @throws {AssertionError} if the item is not of type number, or isFinite(item) is false, i.e., if the item is NaN, Infinity, or -Infinity.
249
+ * @throws {AssertieError} if the item is not of type number, or isFinite(item) is false, i.e., if the item is NaN, Infinity, or -Infinity.
311
250
  */
312
251
  export function assertFiniteNumber(item) {
313
252
  if (!import.meta.env.DEV)
314
253
  return;
315
254
  if (typeof item !== "number")
316
- throw new AssertionError(`Provided item was not of type number. Was: ${getTypeNameOfUnknown(item)}`);
255
+ throw new AssertieError(`Provided item was not of type number. Was: ${getTypeNameOfUnknown(item)}`);
317
256
  if (!isFinite(item))
318
- throw new AssertionError(`Provided number was not finite. Was: ${item}`);
257
+ throw new AssertieError(`Provided number was not finite. Was: ${item}`);
319
258
  }
package/lib/types.d.ts ADDED
@@ -0,0 +1,29 @@
1
+ export type UnknownFunction = (...args: any[]) => unknown;
2
+ export type Constructor<T> = abstract new (...args: any[]) => T;
3
+ export type PrimitiveTypes = {
4
+ "string": string;
5
+ "number": number;
6
+ "boolean": boolean;
7
+ "bigint": bigint;
8
+ "undefined": undefined;
9
+ "function": UnknownFunction;
10
+ "object": object;
11
+ "symbol": symbol;
12
+ };
13
+ export type PrimitiveTypeStrings = keyof PrimitiveTypes;
14
+ export type NullableKeys<T> = {
15
+ [K in keyof T]-?: undefined extends T[K] ? K : null extends T[K] ? K : never;
16
+ }[keyof T];
17
+ export type PropsNonNullable<T, N extends NullableKeys<T>> = T & {
18
+ [K in N]-?: NonNullable<T[K]>;
19
+ };
20
+ export type AllJSTypes = PrimitiveTypeStrings | null | undefined | Constructor<unknown>;
21
+ export type ResolveAnyJSType<T extends AllJSTypes> = T extends PrimitiveTypeStrings ? PrimitiveTypes[T] : T extends null ? null : T extends undefined ? undefined : T extends Constructor<infer U> ? U : never;
22
+ export type ResolveTuple<T extends readonly AllJSTypes[], U> = U & {
23
+ [K in keyof T]: ResolveAnyJSType<T[K]>;
24
+ };
25
+ export type ResolveReadonlyTuple<T extends readonly AllJSTypes[], U> = U & {
26
+ readonly [K in keyof T]: ResolveAnyJSType<T[K]>;
27
+ };
28
+ export type Tuple<T, N extends number, A extends unknown[] = []> = A["length"] extends N ? A : Tuple<T, N, [...A, T]>;
29
+ export type ReadonlyTuple<T, N extends number, A extends readonly unknown[] = readonly []> = A["length"] extends N ? A : ReadonlyTuple<T, N, readonly [...A, T]>;
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assertie",
3
- "version": "0.3.2",
3
+ "version": "1.0.0",
4
4
  "description": "Debug assertions for TypeScript, auto tree-shaken by vite for production.",
5
5
  "keywords": [
6
6
  "TypeScript",
@@ -33,10 +33,15 @@
33
33
  "vite": ">=2.0.0"
34
34
  },
35
35
  "devDependencies": {
36
- "typescript": "~4.7.0",
37
- "vite": "~2.0.0"
36
+ "@types/node": "24.10.11",
37
+ "typescript": "4.7.4",
38
+ "vite": "2.0.5"
38
39
  },
39
40
  "scripts": {
40
- "build": "tsc"
41
+ "build": "tsc",
42
+ "test": "npm run test:runtime && npm run test:types",
43
+ "test:runtime": "npm run test:runtime:check && vite build --mode development -c test/runtime/vite.config.ts && node .test-build/test.js",
44
+ "test:runtime:check": "tsc -p test/runtime/tsconfig.json",
45
+ "test:types": "node test/types/run.ts"
41
46
  }
42
47
  }
@@ -0,0 +1,63 @@
1
+ import { AllJSTypes, ResolveAnyJSType, PrimitiveTypeStrings } from "./types";
2
+
3
+ /**
4
+ * Gets the display name of an expected type for error messages.
5
+ * @param {AllJSTypes} expectedType - The expected type value.
6
+ * @returns {string} The normalized name of the expected type.
7
+ */
8
+ export function getNameOfExpectedType(expectedType: AllJSTypes): string {
9
+ if (expectedType === null) return "null";
10
+ if (expectedType === undefined) return "undefined";
11
+ if (typeof expectedType === "string") return expectedType;
12
+ return expectedType.name;
13
+ }
14
+
15
+ /**
16
+ * Gets the runtime type name of an unknown item for error messages.
17
+ * @param {unknown} item - The item whose runtime type name should be determined.
18
+ * @returns {string} The runtime type name of item.
19
+ */
20
+ export function getTypeNameOfUnknown(item: unknown): string {
21
+ if (item === null) return "null";
22
+ const type = typeof item;
23
+ switch (type) {
24
+ case "object":
25
+ case "function":
26
+ try {
27
+ const unsafe: any = item; // We are using try catch for the fail cases
28
+ if (unsafe instanceof unsafe.constructor) {
29
+ return unsafe.constructor.name;
30
+ }
31
+ } catch {
32
+ }
33
+ const typeStr = Object.prototype.toString.call(item);
34
+ return typeStr.slice(8, -1); // "[object Type]" -> "Type"
35
+ default:
36
+ return type;
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Checks whether the provided item is of the expectedType.
42
+ * @param {unknown} item - The item to check.
43
+ * @param {AllJSTypes} expectedType - The expected type to check against.
44
+ * @returns {boolean} `true` if item's type matches expectedType.
45
+ */
46
+ export function isType<T extends AllJSTypes>(item: unknown, expectedType: T): item is ResolveAnyJSType<T> {
47
+ if (typeof item === expectedType) return true; // correct primitive type
48
+ // Now, if the expectedType is a PrimitiveTypeString,
49
+ // the item is guaranteed to be of the wrong type since it didn't match the typeof check above
50
+ if (typeof expectedType === "string") return false;
51
+ const expectedUndefNullOrConstructor = expectedType as Exclude<typeof expectedType, PrimitiveTypeStrings>;
52
+
53
+ // The type restriction on T guarantees that item is now either undefined, null, or a constructor
54
+ if (item === expectedUndefNullOrConstructor) return true; // correct undefined, null, or constructor of itself
55
+ // i.e. const MyType = Date; isType(Date, Date) && isType(MyType, Date) are both true
56
+ if (expectedUndefNullOrConstructor === null || expectedUndefNullOrConstructor === undefined) return false;
57
+ const expectedConstructor = expectedType as Exclude<typeof expectedUndefNullOrConstructor, null | undefined>;
58
+
59
+ // Lastly, check if the item is an instance of the provided constructor
60
+ if (item instanceof expectedConstructor) return true;
61
+
62
+ return false;
63
+ }