assertie 0.1.0 → 0.2.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 ADDED
@@ -0,0 +1,11 @@
1
+ # Changelog
2
+
3
+ ## [0.2.0](https://github.com/OfficialHalfwayDead/assertie/compare/v0.1.0...v0.2.0) (2025-02-17)
4
+
5
+ ### Breaking Changes
6
+
7
+ * [`a721e02`](https://github.com/OfficialHalfwayDead/assertie/commit/a721e02b2e8b7378f4dc017e02c2dd48ba899bfb) Renamed all `assertTypeof` to `assertTypeOf` for readability and consistency with `assertInstanceOf`. Sorry for the instant breaking change if anyone was already using it. Better now than carrying that inconsistency around forever.
8
+
9
+ ### Features
10
+
11
+ * [`76ff555`](https://github.com/OfficialHalfwayDead/assertie/commit/76ff555cbb3a17d27c07642b078f96cd807812ba) Add `assertNull` as it was the only option in `assertType(val, null)` that didn't have an individual function counterpart.
package/README.md CHANGED
@@ -2,15 +2,24 @@
2
2
 
3
3
  Debug assertions for TypeScript, auto tree-shaken by vite for production.
4
4
 
5
- Why? Because asserts are simple to read and safer than casting. Use them when you know something is guaranteed to be true, and assertie will make sure it is in dev builds. As programmers, we sometimes make wrong assumptions.
5
+ Why? Because asserts are simple to read and safer than casting. As programmers, we sometimes make wrong assumptions. Use them when you know something is guaranteed to be true, and assertie will make sure it actually is in dev builds.
6
6
 
7
7
  ```ts
8
8
  import { assertInstanceOf } from "assertie";
9
9
  ...
10
+
10
11
  const original = document.getElementById("probably-mounted");
11
- if (original === null) return; // This isn't the place for an assert because the element isn't guaranteed to be present.
12
- const clone = original.cloneNode(true); // returns type Node but we know it'll always be an HTMLElement
12
+
13
+ // If the element isn’t found, we exit here.
14
+ // Asserts are not meant for validating uncertain values.
15
+ if (original === null) return;
16
+
17
+ // cloneNode returns type Node, but we know it will always
18
+ // be an HTMLElement, because `original` was one.
19
+ const clone = original.cloneNode(true);
13
20
  assertInstanceOf(clone, HTMLElement);
21
+ // Unlike casting, the assert will throw if you were mistaken,
22
+ // or if someone accidentally changed const original = document;
14
23
  clone.innerText = "No `as` cast needed! 0 overhead in production.";
15
24
  ```
16
25
 
@@ -53,7 +62,8 @@ const config: UserConfig = {
53
62
  ```ts
54
63
  import { assert } from "assertie";
55
64
 
56
- assert(typeof "yup" === "string", "optional text if assertion fails");
65
+ const a = "yup";
66
+ assert(a === "yup", "optional text if assertion fails");
57
67
 
58
68
  // You get type narrowing from assertie's assertions
59
69
  const x: boolean = true;
@@ -66,7 +76,8 @@ const y: true = x; // no error
66
76
  ```ts
67
77
  import { assertType } from "assertie";
68
78
 
69
- // assertType can take any primitive JS type string (e.g., "number", "string"), null, undefined, or a class/constructable
79
+ // assertType can take null, undefined, a class/constructable
80
+ // or a primitive JS type string (e.g., "number")
70
81
  assertType(1, "number");
71
82
  assertType(() => {}, "function");
72
83
  assertType(undefined, "undefined");
@@ -84,14 +95,15 @@ const good: string = value; // no `as` needed
84
95
  You don't need to use strings to narrow primitives. There are specific functions for specific types if you prefer that.
85
96
 
86
97
  ```ts
87
- assertTypeofString("yup");
88
- assertTypeofNumber(123);
89
- assertTypeofBoolean(true);
90
- assertTypeofBigint(123n);
91
- assertTypeofUndefined(undefined);
92
- assertTypeofFunction(() => {});
93
- assertTypeofObject({});
94
- assertTypeofSymbol(Symbol("yup"));
98
+ assertTypeOfString("yup");
99
+ assertTypeOfNumber(123);
100
+ assertTypeOfBoolean(true);
101
+ assertTypeOfBigint(123n);
102
+ assertTypeOfUndefined(undefined);
103
+ assertNull(null); // different because typeof null === "object"
104
+ assertTypeOfFunction(() => {});
105
+ assertTypeOfObject({});
106
+ assertTypeOfSymbol(Symbol("yup"));
95
107
  assertInstanceOf(new Date(), Date);
96
108
  ```
97
109
 
@@ -105,7 +117,9 @@ let hoisted: string | null | undefined = null;
105
117
  const f = () => {
106
118
  assertNonNullable(hoisted);
107
119
  // vs.
108
- if (hoisted === null || hoisted === undefined) return;
120
+ if (hoisted === null || hoisted === undefined) {
121
+ return;
122
+ }
109
123
 
110
124
  console.log(hoisted.toUpperCase());
111
125
  };
@@ -116,10 +130,10 @@ f();
116
130
 
117
131
  There are multiple ways in which an assert is better in this specific case:
118
132
 
119
- 1. Making the code intention clear. Your function was never meant to only run some of the time. It is always supposed to work. You only added the if statement to make the compiler happy.
120
- 2. The assert will throw an error in dev if the case that should never happen does happen. Without an error, it would be easy to change how the hoisted variable is set, and the potential behavior change is more likely to go unnoticed.
133
+ 1. Making the code intention clear. `f` was never meant to only run its body some of the time. It is always supposed to work. But the if statement was required to make the compiler happy.
134
+ 2. The assert will throw an error in dev if the case that should never happen does happen. Without the assert, any potential behavior change due to `hoisted` not being set is more likely to go unnoticed.
121
135
  3. It's a little shorter, mainly if you have to check null and undefined and maybe have prettier rules for { brackets } on if statements.
122
- 4. The assert will be removed in production, so there's no overhead. If that makes you uncomfortable, you can just leave both in.
136
+ 4. The assert will be removed in production, so there's no overhead. If that makes you uncomfortable, you can just can still put the if statement below the assert and reap the benefits of the first two points.
123
137
 
124
138
  ```ts
125
139
  // Sometimes not your entire object is null
@@ -138,11 +152,14 @@ const safeObj = obj;
138
152
  // typeof safeObj === { a: string, b: string, c: number }
139
153
  ```
140
154
 
141
- The reason an array is needed here is because undefined properties may not be present in `Object.keys`, so the caller needs to provide all keys to check. Don't worry about the safety, though. If you forget to pass a key, it will remain undefined/null after the assert.
155
+ The reason an array is needed here is because undefined properties may not be present in `Object.keys`, so the caller needs to provide all keys to check. Don't worry about the safety, though. If you forget to pass a key, its type will remain nullable after the assert and TypeScript will not consider it safe to access.
142
156
 
143
157
  ### Asserting unreachable code
144
158
 
145
- The unreachable assertion can both help you ensure that switch/if statements are exhaustive at compile time and throw at runtime if the TypeScript types were inaccurate somewhere.
159
+ The unreachable assertion will
160
+
161
+ 1. ensure switch/if statements are exhaustive at compile time.
162
+ 2. throw an error at runtime if TypeScript types are inaccurate.
146
163
 
147
164
  ```ts
148
165
  const x: "a" | "b" = "a";
@@ -165,8 +182,8 @@ For now, there is only one:
165
182
 
166
183
  ```ts
167
184
  assertFiniteNumber(123);
168
- // Ensures passed value is typeof number and finite
185
+ // Ensures passed value is typeof number and isFinite(num)
169
186
  // DO NOT USE FOR INPUT VALIDATION OF USER PROVIDED VALUES!
170
187
  ```
171
188
 
172
- Useful for string-to-number conversions when you expect valid number strings. Prevents accidental usage of strings or invalid numbers due to JavaScript's loose equality (`123 == "123"`).
189
+ Useful for string-to-number conversions when you expect **valid** number strings. Prevents accidental usage of strings or invalid numbers due to JS's loose equality (`123 == "123"`).
package/lib/index.d.ts CHANGED
@@ -20,14 +20,15 @@ type AllJSTypes = PrimitiveTypeStrings | null | undefined | Constructor<unknown>
20
20
  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;
21
21
  export declare function assert(hasToBeTrue: boolean, msg?: string): asserts hasToBeTrue is true;
22
22
  export declare function assertType<T extends AllJSTypes>(obj: unknown, expectedType: T): asserts obj is ResolveAnyJSType<T>;
23
- export declare function assertTypeofString(obj: unknown): asserts obj is string;
24
- export declare function assertTypeofNumber(obj: unknown): asserts obj is number;
25
- export declare function assertTypeofBoolean(obj: unknown): asserts obj is boolean;
26
- export declare function assertTypeofBigint(obj: unknown): asserts obj is bigint;
27
- export declare function assertTypeofUndefined(obj: unknown): asserts obj is undefined;
28
- export declare function assertTypeofFunction(obj: unknown): asserts obj is Function;
29
- export declare function assertTypeofObject(obj: unknown): asserts obj is object;
30
- export declare function assertTypeofSymbol(obj: unknown): asserts obj is symbol;
23
+ export declare function assertTypeOfString(obj: unknown): asserts obj is string;
24
+ export declare function assertTypeOfNumber(obj: unknown): asserts obj is number;
25
+ export declare function assertTypeOfBoolean(obj: unknown): asserts obj is boolean;
26
+ export declare function assertTypeOfBigint(obj: unknown): asserts obj is bigint;
27
+ export declare function assertTypeOfUndefined(obj: unknown): asserts obj is undefined;
28
+ export declare function assertTypeOfFunction(obj: unknown): asserts obj is Function;
29
+ export declare function assertTypeOfObject(obj: unknown): asserts obj is object;
30
+ export declare function assertTypeOfSymbol(obj: unknown): asserts obj is symbol;
31
+ export declare function assertNull(obj: unknown): asserts obj is null;
31
32
  export declare function assertInstanceOf<T>(obj: unknown, constructable: Constructor<T>): asserts obj is T;
32
33
  export declare function assertUnreachable(obj: never, msg?: string): asserts obj is never;
33
34
  export declare function assertPropsNonNullable<T, N extends NullableKeys<T>>(obj: T, props: N[]): asserts obj is PropsNonNullable<T, N>;
package/lib/index.js CHANGED
@@ -23,55 +23,61 @@ export function assertType(obj, expectedType) {
23
23
  return;
24
24
  throw new AssertionError(`Provided object was not of type ${(typeof expectedType !== "string") ? expectedType?.name : expectedType ?? expectedType}. Was: ${(obj === null) ? "null" : obj?.constructor?.name ?? typeof obj}, value: ${obj}`);
25
25
  }
26
- export function assertTypeofString(obj) {
26
+ export function assertTypeOfString(obj) {
27
27
  if (!import.meta.env.DEV)
28
28
  return;
29
29
  if (typeof obj !== "string")
30
30
  throw new AssertionError(`Provided object was not of type string. Was: ${typeof obj}`);
31
31
  }
32
- export function assertTypeofNumber(obj) {
32
+ export function assertTypeOfNumber(obj) {
33
33
  if (!import.meta.env.DEV)
34
34
  return;
35
35
  if (typeof obj !== "number")
36
36
  throw new AssertionError(`Provided object was not of type number. Was: ${typeof obj}`);
37
37
  }
38
- export function assertTypeofBoolean(obj) {
38
+ export function assertTypeOfBoolean(obj) {
39
39
  if (!import.meta.env.DEV)
40
40
  return;
41
41
  if (typeof obj !== "boolean")
42
42
  throw new AssertionError(`Provided object was not of type boolean. Was: ${typeof obj}`);
43
43
  }
44
- export function assertTypeofBigint(obj) {
44
+ export function assertTypeOfBigint(obj) {
45
45
  if (!import.meta.env.DEV)
46
46
  return;
47
47
  if (typeof obj !== "bigint")
48
48
  throw new AssertionError(`Provided object was not of type bigint. Was: ${typeof obj}`);
49
49
  }
50
- export function assertTypeofUndefined(obj) {
50
+ export function assertTypeOfUndefined(obj) {
51
51
  if (!import.meta.env.DEV)
52
52
  return;
53
53
  if (typeof obj !== "undefined")
54
54
  throw new AssertionError(`Provided object was not of type undefined. Was: ${typeof obj}`);
55
55
  }
56
56
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
57
- export function assertTypeofFunction(obj) {
57
+ export function assertTypeOfFunction(obj) {
58
58
  if (!import.meta.env.DEV)
59
59
  return;
60
60
  if (typeof obj !== "function")
61
61
  throw new AssertionError(`Provided object was not of type function. Was: ${typeof obj}`);
62
62
  }
63
- export function assertTypeofObject(obj) {
63
+ export function assertTypeOfObject(obj) {
64
64
  if (!import.meta.env.DEV)
65
65
  return;
66
66
  if (typeof obj !== "object")
67
67
  throw new AssertionError(`Provided object was not of type object. Was: ${typeof obj}`);
68
68
  }
69
- export function assertTypeofSymbol(obj) {
69
+ export function assertTypeOfSymbol(obj) {
70
70
  if (!import.meta.env.DEV)
71
71
  return;
72
72
  if (typeof obj !== "symbol")
73
73
  throw new AssertionError(`Provided object was not of type symbol. Was: ${typeof obj}`);
74
74
  }
75
+ export function assertNull(obj) {
76
+ if (!import.meta.env.DEV)
77
+ return;
78
+ if (obj !== null)
79
+ throw new AssertionError(`Provided object was not null. Was: ${obj}`);
80
+ }
75
81
  export function assertInstanceOf(obj, constructable) {
76
82
  if (!import.meta.env.DEV)
77
83
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assertie",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Debug assertions for TypeScript, auto tree-shaken by vite for production.",
5
5
  "keywords": [
6
6
  "TypeScript",
package/src/index.ts CHANGED
@@ -50,47 +50,52 @@ export function assertType<T extends AllJSTypes>(obj: unknown, expectedType: T):
50
50
  throw new AssertionError(`Provided object was not of type ${(typeof expectedType !== "string") ? expectedType?.name : expectedType ?? expectedType}. Was: ${(obj === null) ? "null" : obj?.constructor?.name ?? typeof obj}, value: ${obj}`);
51
51
  }
52
52
 
53
- export function assertTypeofString(obj: unknown): asserts obj is string {
53
+ export function assertTypeOfString(obj: unknown): asserts obj is string {
54
54
  if (!import.meta.env.DEV) return;
55
55
  if (typeof obj !== "string") throw new AssertionError(`Provided object was not of type string. Was: ${typeof obj}`);
56
56
  }
57
57
 
58
- export function assertTypeofNumber(obj: unknown): asserts obj is number {
58
+ export function assertTypeOfNumber(obj: unknown): asserts obj is number {
59
59
  if (!import.meta.env.DEV) return;
60
60
  if (typeof obj !== "number") throw new AssertionError(`Provided object was not of type number. Was: ${typeof obj}`);
61
61
  }
62
62
 
63
- export function assertTypeofBoolean(obj: unknown): asserts obj is boolean {
63
+ export function assertTypeOfBoolean(obj: unknown): asserts obj is boolean {
64
64
  if (!import.meta.env.DEV) return;
65
65
  if (typeof obj !== "boolean") throw new AssertionError(`Provided object was not of type boolean. Was: ${typeof obj}`);
66
66
  }
67
67
 
68
- export function assertTypeofBigint(obj: unknown): asserts obj is bigint {
68
+ export function assertTypeOfBigint(obj: unknown): asserts obj is bigint {
69
69
  if (!import.meta.env.DEV) return;
70
70
  if (typeof obj !== "bigint") throw new AssertionError(`Provided object was not of type bigint. Was: ${typeof obj}`);
71
71
  }
72
72
 
73
- export function assertTypeofUndefined(obj: unknown): asserts obj is undefined {
73
+ export function assertTypeOfUndefined(obj: unknown): asserts obj is undefined {
74
74
  if (!import.meta.env.DEV) return;
75
75
  if (typeof obj !== "undefined") throw new AssertionError(`Provided object was not of type undefined. Was: ${typeof obj}`);
76
76
  }
77
77
 
78
78
  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
79
- export function assertTypeofFunction(obj: unknown): asserts obj is Function {
79
+ export function assertTypeOfFunction(obj: unknown): asserts obj is Function {
80
80
  if (!import.meta.env.DEV) return;
81
81
  if (typeof obj !== "function") throw new AssertionError(`Provided object was not of type function. Was: ${typeof obj}`);
82
82
  }
83
83
 
84
- export function assertTypeofObject(obj: unknown): asserts obj is object {
84
+ export function assertTypeOfObject(obj: unknown): asserts obj is object {
85
85
  if (!import.meta.env.DEV) return;
86
86
  if (typeof obj !== "object") throw new AssertionError(`Provided object was not of type object. Was: ${typeof obj}`);
87
87
  }
88
88
 
89
- export function assertTypeofSymbol(obj: unknown): asserts obj is symbol {
89
+ export function assertTypeOfSymbol(obj: unknown): asserts obj is symbol {
90
90
  if (!import.meta.env.DEV) return;
91
91
  if (typeof obj !== "symbol") throw new AssertionError(`Provided object was not of type symbol. Was: ${typeof obj}`);
92
92
  }
93
93
 
94
+ export function assertNull(obj: unknown): asserts obj is null {
95
+ if (!import.meta.env.DEV) return;
96
+ if (obj !== null) throw new AssertionError(`Provided object was not null. Was: ${obj}`);
97
+ }
98
+
94
99
  export function assertInstanceOf<T>(obj: unknown, constructable: Constructor<T>): asserts obj is T {
95
100
  if (!import.meta.env.DEV) return;
96
101
  if (!(obj instanceof constructable)) throw new AssertionError(`Provided object was not of type ${constructable.name} but was type: ${(obj === null) ? "null" : obj?.constructor?.name ?? typeof obj}, value: ${obj}`);