assertie 0.3.1 → 0.3.2

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.2](https://github.com/OfficialHalfwayDead/assertie/compare/v0.3.1...v0.3.2) (2025-02-27)
4
+
5
+ * [`0814dd2`](https://github.com/OfficialHalfwayDead/assertie/commit/0814dd2a6b9daf2bbeb99e2925710cc8a76caf07) Bugfix: Constructor type wasn't properly typed and prevent `assertInstanceOf` and `assertType` from accepting many construcable types.
6
+ * [`940e4e4`](https://github.com/OfficialHalfwayDead/assertie/commit/940e4e424c14db20734ed4e2ec2b8a6eeae3aef3) Clarify SSR vite settings and Svelte/Proxy pitfalls in the README.
7
+
8
+
3
9
  ## [0.3.1](https://github.com/OfficialHalfwayDead/assertie/compare/v0.3.0...v0.3.1) (2025-02-23)
4
10
 
5
11
  * [`0d59837`](https://github.com/OfficialHalfwayDead/assertie/commit/0d59837841707c963ce174e79a527fcb1379ac4f) Add array and tuple assertions to the README.
package/README.md CHANGED
@@ -29,6 +29,23 @@ clone.innerText = "No `as` cast needed! 0 overhead in production.";
29
29
  npm i -D assertie
30
30
  ```
31
31
 
32
+ By default, vite will tree-shake the functions in the frontend, but for SSR it will actually not touch libraries unless you specify that the module should not be externalized.
33
+
34
+ ```ts
35
+ // vite.config.ts
36
+ const config: UserConfig = {
37
+ build: {
38
+ ssr: { // crucial if you have SSR
39
+ noExternal: ["assertie"],
40
+ },
41
+ rollupOptions: {
42
+ treeshake: true, // this is default
43
+ // just make sure it's not explicitly false
44
+ },
45
+ },
46
+ };
47
+ ```
48
+
32
49
  If you're getting errors when using the package, it's likely because your TypeScript targets are too low:
33
50
 
34
51
  ```json
@@ -42,18 +59,6 @@ If you're getting errors when using the package, it's likely because your TypeSc
42
59
  }
43
60
  ```
44
61
 
45
- By default, vite will tree-shake the functions for production, but make sure you haven't specifically disabled it in your vite config:
46
-
47
- ```ts
48
- // vite.config.ts
49
- const config: UserConfig = {
50
- build: {
51
- rollupOptions: {
52
- treeshake: true,
53
- },
54
- },
55
- };
56
- ```
57
62
 
58
63
  ## Usage
59
64
 
@@ -76,7 +81,7 @@ const y: true = x; // no error
76
81
  ```ts
77
82
  import { assertType } from "assertie";
78
83
 
79
- // assertType can take null, undefined, a class/constructable
84
+ // assertType can take null, undefined, a class/constructable,
80
85
  // or a primitive JS type string (e.g., "number")
81
86
  assertType(1, "number");
82
87
  assertType(() => {}, "function");
@@ -109,7 +114,7 @@ assertInstanceOf(new Date(), Date);
109
114
 
110
115
  ### Asserting non-null
111
116
 
112
- Sometimes you'll find yourself in a situation where you know from the calling context that a hoisted variable is not `null` or `undefined`, but TypeScript doesn't.
117
+ Sometimes, you'll find yourself in a situation where you know from the calling context that a hoisted variable is not `null` or `undefined`, but TypeScript doesn't.
113
118
 
114
119
  ```ts
115
120
  let hoisted: string | null | undefined = null;
@@ -128,9 +133,9 @@ hoisted = "yup";
128
133
  f();
129
134
  ```
130
135
 
131
- There are multiple ways in which an assert is better in this specific case:
136
+ There are multiple advantages to using an assertion in this case:
132
137
 
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.
138
+ It clarifies the code's intent. f was never meant to conditionally execute its body. It is always supposed to work, but the if statement was required to satisfy the compiler.
134
139
  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.
135
140
  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.
136
141
  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.
@@ -156,7 +161,7 @@ The reason an array is needed here is because undefined properties may not be pr
156
161
 
157
162
  ### Arrays and tuples
158
163
 
159
- Arrays and tuples have equivalent versions of `assertType` and `assertNonNullable`. These make it easy to check every element at once and get great errors and type narrowing.
164
+ Arrays and tuples have equivalent versions of `assertType` and `assertNonNullable`. These make it easy to check every element at once and provide excellent error messages and type narrowing.
160
165
 
161
166
  ```ts
162
167
  const arr: (number | string | null)[] = [1, 2, 3];
@@ -181,7 +186,7 @@ const tup: [number, string] = arrMixed;
181
186
  The unreachable assertion will
182
187
 
183
188
  1. ensure switch/if statements are exhaustive at compile time.
184
- 2. throw an error at runtime if TypeScript types are inaccurate.
189
+ 2. throw an error at runtime if some TypeScript types are inaccurate.
185
190
 
186
191
  ```ts
187
192
  const x: "a" | "b" = "a";
@@ -217,3 +222,42 @@ const num = Number(numStr); // NaN
217
222
  assertFiniteNumber(num); // throws
218
223
  arr[num] = "yup" // disaster averted
219
224
  ```
225
+
226
+
227
+ ## Pitfalls
228
+
229
+ While assertions will never throw in production, complete removal of the code may not happen if you call another function inside the assertion call:
230
+
231
+ ```js
232
+ assert(object.foo() === "yup");
233
+
234
+ // bundler leaves this stub:
235
+ function assert(hasToBeTrue, msg = "No specific message provided.") {
236
+ return;
237
+ }
238
+ ```
239
+
240
+ Since `foo()` might have side effects, it is not possible to remove the entire line. And it seems, the vite bundler **is not capable** of turning the code into:
241
+
242
+ ```ts
243
+ // stays because of potential side effects
244
+ const assertValue = object.foo() === "yup";
245
+ assert(assertValue); // gets removed now
246
+ ```
247
+
248
+ Therefore, you'll have to do that yourself, or if you know `foo()` is a pure function, you can mark it as such:
249
+
250
+ ```ts
251
+ assert(/* @__PURE__ */ object.foo() === "yup");
252
+ ```
253
+
254
+ ### Svelte
255
+
256
+ Accessing the value of a rune `x` compiles to `get(x)`, leading to the same pitfall as above. To prevent this, you need to treat the rune like a function:
257
+
258
+ ```ts
259
+ let rune = $state(1);
260
+ let otherRune = $state(1);
261
+
262
+ assert(/*@__PURE__*/ rune === /*@__PURE__*/ otherRune);
263
+ ```
package/lib/index.d.ts CHANGED
@@ -16,7 +16,7 @@ declare type NullableKeys<T> = {
16
16
  declare type PropsNonNullable<T, N extends NullableKeys<T>> = T & {
17
17
  [K in N]-?: NonNullable<T[K]>;
18
18
  };
19
- declare type Constructor<T> = new (...args: unknown[]) => T;
19
+ declare type Constructor<T> = new (...args: any[]) => T;
20
20
  declare type AllJSTypes = PrimitiveTypeStrings | null | undefined | Constructor<unknown>;
21
21
  declare 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
22
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assertie",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
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
@@ -22,7 +22,7 @@ type PropsNonNullable<T, N extends NullableKeys<T>> = T & {
22
22
  [K in N]-?: NonNullable<T[K]>;
23
23
  };
24
24
 
25
- type Constructor<T> = new (...args: unknown[]) => T;
25
+ type Constructor<T> = new (...args: any[]) => T;
26
26
 
27
27
  type AllJSTypes = PrimitiveTypeStrings | null | undefined | Constructor<unknown>;
28
28