@vicin/sigil 2.2.1 β†’ 3.1.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 CHANGED
@@ -2,6 +2,37 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [3.1.0] - 2026-02-25
6
+
7
+ ### Added
8
+
9
+ - `isExactType` is added to check for exact instances (children are ingored as well)
10
+
11
+ ### Removed
12
+
13
+ - `SigilOptions.skipLabelInheritanceCheck` is removed.
14
+ - `isOfTypeStrict` is removed.
15
+
16
+ ## [3.0.0] - 2026-02-24
17
+
18
+ ### Added
19
+
20
+ - `sigil` symbol used for type-only nominal branding of classes
21
+
22
+ ### Changed
23
+
24
+ - `__SIGIL_BRAND__` is classes replaced with `sigil` symbol
25
+
26
+ ### Removed
27
+
28
+ - `withSigilTyped` is removed as library moved into manual branding
29
+
30
+ ### Breaking changes
31
+
32
+ - `withSigilTyped` is removed as library moved into manual branding
33
+ - `SigilBrandOf` is renamed to `SigilOf`
34
+ - `UpdateSigilBrand` is renamed to `ExtendSigil`
35
+
5
36
  ## [2.2.1] - 2026-02-23
6
37
 
7
38
  ### Added
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Sigil
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@vicin/sigil.svg)](https://www.npmjs.com/package/@vicin/sigil) [![npm downloads](https://img.shields.io/npm/dm/@vicin/sigil.svg)](https://www.npmjs.com/package/@vicin/sigil) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue) [![Build](https://github.com/ZiadTaha62/sigil/actions/workflows/ci.yml/badge.svg)](https://github.com/ZiadTaha62/sigil/actions/workflows/ci.yml)
3
+ [![npm version](https://img.shields.io/npm/v/@vicin/sigil.svg)](https://www.npmjs.com/package/@vicin/sigil) [![npm downloads](https://img.shields.io/npm/dm/@vicin/sigil.svg)](https://www.npmjs.com/package/@vicin/sigil) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) ![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue) [![Build](https://github.com/ZiadTaha62/sigil/actions/workflows/ci.yml/badge.svg)](https://github.com/ZiadTaha62/sigil/actions/workflows/ci.yml) ![bundle size](https://img.shields.io/bundlephobia/minzip/@vicin/sigil)
4
4
 
5
- > - πŸŽ‰ v2.0.0 is out! Happy coding! πŸ˜„πŸ’»
5
+ > - πŸŽ‰ v3.0.0 is out! Happy coding! πŸ˜„πŸ’»
6
6
  > - πŸ“„ **Changelog:** [CHANGELOG.md](./CHANGELOG.md)
7
7
 
8
8
  `Sigil` replaces `instanceof` across bundles, enforces nominal class identity, and makes inheritance-aware runtime type checks reliable in large TypeScript systems. It organizes class identities across your codebase and gives you the power of **nominal typing** and **safe cross-bundle class checks** where each class constructor is stored under a unique label.
@@ -15,14 +15,17 @@
15
15
 
16
16
  ## Important Notes Before Using
17
17
 
18
- - **Explicit class identity:** `Sigil` uses passed class label to identify classes, which means that dev is responsible for uniqueness of classes by passing unique labels.
19
- - **Performance:** Minimal overhead, but `.isOfType()` is slightly slower than native `instanceof`. Avoid in ultra-hot paths.
20
- - **Private Constructors:** HOF pattern allows extending private constructors in types (TypeScript limitation).
18
+ - **Explicit class identity:** `Sigil` uses passed class label to identify classes, which means that the developer is responsible for uniqueness of classes by passing unique labels.
21
19
  - **Simple instanceof Fix:** If you just need runtime checks without extras, see the [minimal mode](#minimal-mode).
22
20
 
23
- ## Why Registry is dropped
21
+ ## Features
24
22
 
25
- In v2 we simplified the architecture to remove global registries and reduce complexity across packages.
23
+ - βœ… **Drop-in `instanceof` replacement** that works across bundles, HMR, and monorepos
24
+ - βœ… **True nominal typing** with zero runtime cost
25
+ - βœ… **Inheritance-aware** checks (`isOfType` knows about subclasses)
26
+ - βœ… **Tiny less than 1.5 KB minified and brotlied** measured using size-limit
27
+ - βœ… **Performant as native instanceof** but with guaranteed checks! Also can check for **exact class instance**
28
+ - βœ… Full TypeScript 5.0+ support + excellent JSDoc
26
29
 
27
30
  ---
28
31
 
@@ -33,24 +36,17 @@ In v2 we simplified the architecture to remove global registries and reduce comp
33
36
  - [Basic usage](#basic-usage)
34
37
  - [Decorator pattern](#decorator-pattern)
35
38
  - [HOF pattern](#hof-higher-order-function-pattern)
36
- - [Minimal β€œfirst-run” example](#minimal-first-run-example)
37
39
  - [Migration](#migration)
38
- - [Limitations & guarantees](#limitations--guarantees)
39
- - [What Sigil guarantees](#what-sigil-guarantees)
40
- - [What Sigil does not guarantee](#what-sigil-does-not-guarantee)
41
40
  - [Core concepts](#core-concepts)
42
41
  - [Terminology](#terminology)
43
42
  - [Purpose and Origins](#purpose-and-origins)
44
43
  - [Implementation Mechanics](#implementation-mechanics)
45
- - [Nominal typing patterns](#nominal-typing-patterns)
46
- - [HOF pattern](#1-hof-pattern-_classclass)
47
- - [Decorator pattern](#2-decorator-pattern)
44
+ - [Inheritance example](#inheritance-example)
48
45
  - [API reference](#api-reference)
49
46
  - [Options & configuration](#options--configuration)
50
47
  - [Minimal mode](#minimal-mode)
51
48
  - [Strict mode](#strict-mode)
52
- - [## Which pattern should I use?](#which-pattern-should-i-use)
53
- - [Troubleshooting & FAQ](#troubleshooting--faq)
49
+ - [Benchmarks](#benchmarks)
54
50
  - [Contributing](#contributing)
55
51
  - [License](#license)
56
52
  - [Author](#author)
@@ -92,10 +88,8 @@ If your class is marked with `abstract`:
92
88
  ```ts
93
89
  import { Sigil, SigilifyAbstract } from '@vicin/sigil';
94
90
 
95
- // Using the pre-sigilified base class:
96
91
  abstract class User extends Sigil {}
97
92
 
98
- // Or use Sigilify when you want an ad-hoc class:
99
93
  const MyClass = SigilifyAbstract(abstract class {}, '@myorg/mypkg.MyClass');
100
94
  ```
101
95
 
@@ -118,7 +112,7 @@ class User extends Sigil {}
118
112
 
119
113
  ##### HOF (Higher-Order Function) pattern
120
114
 
121
- Apply a label using HOF as `withSigil` or `withSigilTyped`:
115
+ Apply a label using `withSigil` HOF:
122
116
 
123
117
  ```ts
124
118
  import { Sigil, withSigil } from '@vicin/sigil';
@@ -130,26 +124,6 @@ const user = new User();
130
124
  console.log(User.SigilLabel); // "@myorg/mypkg.User"
131
125
  ```
132
126
 
133
- > Note: When extending an already sigilified class (for example `Sigil`), you must decorate the subclass or use the HOF helpers in DEV mode unless you configured the library otherwise.
134
-
135
- ### Minimal β€œfirst-run” example
136
-
137
- ```ts
138
- import { Sigil, withSigil } from '@vicin/sigil';
139
-
140
- class _User extends Sigil {
141
- constructor(public name: string) {
142
- super();
143
- }
144
- }
145
- export const User = withSigil(_User, '@myorg/mypkg.User');
146
-
147
- const u = new User('alice');
148
-
149
- console.log(User.SigilLabel); // "@myorg/mypkg.User"
150
- console.log(User.isOfType(u)); // true
151
- ```
152
-
153
127
  ### Migration
154
128
 
155
129
  Migrating old code into `Sigil` can be done with extra couple lines of code only:
@@ -174,33 +148,15 @@ Congratulations β€” you’ve opted into `Sigil` and you can start replacing `ins
174
148
 
175
149
  ---
176
150
 
177
- ## Limitations & guarantees
178
-
179
- This section states clearly what `Sigil` provides and what it does **not** provide.
180
-
181
- ### What Sigil guarantees
182
-
183
- **1. Reliable runtime identity (when used as intended).**
184
-
185
- **2. Nominal typing that is inheritance-aware**
186
-
187
- ### What Sigil does not guarantee
188
-
189
- **1. Doesn't work across isolated realms (e.g., iframes, workers) without custom bridging.**
190
-
191
- **2. Not for security/access control β€” constructors can be discoverable.**
192
-
193
- ---
194
-
195
151
  ## Core concepts
196
152
 
197
153
  ### Terminology
198
154
 
199
- - **Label**: An identity (string) such as `@scope/pkg.ClassName`, but can be random string (e.g. `@Sigil.auto-dq62ib6jnvmmlfbjhxh2937h`) if no label passed.
200
- - **EffictiveLabel:** A human-readable (string) such as `@scope/pkg.ClassName`, if no label is passed it inherit the last defined label.
155
+ - **Label**: An identity (string) such as `@scope/pkg.ClassName`, but can be random string (e.g. `@Sigil-auto:ClassName:mm2gkdwn:0:g1sq`) if no label passed.
156
+ - **EffectiveLabel:** A human-readable (string) such as `@scope/pkg.ClassName`, if no label is passed it inherit the last defined label.
201
157
  - **Label lineage**: Array of labels for ancestry.
202
158
  - **Label set**: Set of labels for fast checks.
203
- - **Brand**: TypeScript marker (`__SIGIL_BRAND__`) for nominal types.
159
+ - **[sigil]**: TypeScript symbol marker for nominal types.
204
160
 
205
161
  ---
206
162
 
@@ -216,143 +172,85 @@ if (obj instanceof User) { ... }
216
172
 
217
173
  // With Sigil
218
174
  if (User.isOfType(obj)) { ... } // This still works even if User was bundled twice.
175
+ if (User.isExactType(obj)) { ... } // Or check for exactly same constructor not its children
219
176
  ```
220
177
 
221
- - **Manual Branding Overhead:** Custom identifiers lead to boilerplate and maintenance issues.
222
-
223
- `Sigil` abstracts these into a **centralized system**, making identity management **explicit** and **error-resistant** if defined the right way.
224
-
225
- ### Implementation Mechanics
226
-
227
- - **Runtime Contract:** Established via extending `Sigil` or using `Sigilify` mixin.
228
- - **Update metadata:** With each new child, HOF or decorators are used to attach metadata and update nominal type.
229
- - **Accessors & Type guards:** Classes expose `SigilLabel`; instances provide `getSigilLabel()` for querying unique identifier label. also when typed it hold nominal identity used to prevent subtle bugs.
178
+ - **Manual Branding Overhead:** Custom identifiers lead to boilerplate and maintenance issues, `Sigil` add reliable inheritance-aware nominal branding with just one line of code.
230
179
 
231
180
  ```ts
232
- import { Sigil, withSigilTyped, GetInstance } from '@vicin/sigil';
233
-
234
- // Runtime contract
235
- class _MyClass extends Sigil {}
181
+ import { sigil } from '@vicin/sigil';
236
182
 
237
- // Update metadata (append new label)
238
- const MyClass = withSigilTyped(_MyClass, '@scope/package.MyClass');
239
- type MyClass = GetInstance<typeof MyClass>;
183
+ class User extends Sigil {
184
+ declare [sigil]: ExtendSigil<'User', Sigil>; // <-- Update nominal brand with this line
185
+ }
240
186
 
241
- // Accessors & Type guards
242
- console.log(MyClass.SigilLabel); // '@scope/package.MyClass'
243
- console.log(new MyClass().getSigilLabel()); // '@scope/package.MyClass'
244
- console.log(MyClass.isOfType(new MyClass())); // true
245
- function x(c: MyClass) {} // Only instances of 'MyClass' can be passed
187
+ type test1 = User extends Sigil ? true : false; // true
188
+ type test2 = Sigil extends User ? true : false; // false
246
189
  ```
247
190
 
248
- ---
249
-
250
- ## Nominal typing patterns
251
-
252
- In this part we will discuss conventions to avoid any type errors and have nominal typing with just extra few definition lines.
253
- We have two patterns, **HOF pattern (`_Class`/`Class`)** and **Decorator pattern**:
191
+ `Sigil` abstracts these into a **centralized system**, making identity management **explicit** and **error-resistant** if defined the right way.
254
192
 
255
- ### 1. HOF pattern (`_Class`/`Class`)
193
+ ### Implementation Mechanics
256
194
 
257
- Define implementation in an untyped class, then wrap for typing:
195
+ - **Runtime Contract:** Established via extending `Sigil` or using `Sigilify` mixin.
196
+ - **Update metadata:** With each new child, use decorators or HOF to attach run-time metadata and `ExtendSigil` to update nominal type.
258
197
 
259
198
  ```ts
260
- import { Sigil, withSigilTyped, GetInstance } from '@vicin/sigil';
199
+ import { Sigil, WithSigil, sigil, ExtendSigil } from '@vicin/sigil';
261
200
 
262
- class _X extends Sigil {
263
- // Class logic here
201
+ @WithSigil('@scope/package.MyClass') // <-- Run-time values update
202
+ class MyClass extends Sigil {
203
+ declare [sigil]: ExtendSigil<'@scope/package.MyClass', Sigil>; // <-- compile-time type update
264
204
  }
265
- export const X = withSigilTyped(_X, 'Label.X');
266
- export type X = GetInstance<typeof X>;
267
205
  ```
268
206
 
269
- #### `InstanceType<>` vs `GetInstance<>`
270
-
271
- You should depend on `GetInstance` to get type of instance and avoid using `InstanceType` as it returns `any` if the class constructor is `protected` or `private`.
272
-
273
- ```ts
274
- export type X = GetInstance<typeof X>; // <-- works with 'private' and 'protected' constructors as well
275
- ```
276
-
277
- Internally `GetInstance` is just `T extends { prototype: infer R }`.
278
-
279
- #### Generic propagation
207
+ You can avoid decorators and use HOF but they are slightly more verbose:
280
208
 
281
209
  ```ts
282
- class _X<G> extends Sigil {}
283
- export const X = withSigilTyped(_X, 'Label.X');
284
- export type X<G> = GetInstance<typeof X<G>>; // <-- Redeclare generics here
285
-
286
- class _Y<G> extends X<G> {} // and so on...
287
- ```
288
-
289
- #### Anonymous classes
290
-
291
- You may see error: `Property 'x' of exported anonymous class type may not be private or protected.`, although this is rare to occur.
292
- This comes from the fact that all typed classes are `anonymous class` as they are return of HOF. to avoid these error entirely all you need is exporting the untyped classes even if they are un-used as a good convention.
210
+ import { Sigil, withSigil, sigil, ExtendSigil } from '@vicin/sigil';
293
211
 
294
- ```ts
295
- export class _X extends Sigil {} // <-- Just add 'export' here
296
- export const X = withSigilTyped(_X, 'Label.X');
297
- export type X = GetInstance<typeof X>;
298
- ```
299
-
300
- #### Private constructors
301
-
302
- The only limitation in HOF approach is **extending private constructors**:
303
-
304
- ```ts
305
- import { Sigil, withSigilTyped, GetInstance } from '@vicin/sigil';
306
- class _X extends Sigil {
307
- private constructor() {}
212
+ class _MyClass extends Sigil {
213
+ declare [sigil]: ExtendSigil<'@scope/package.MyClass', Sigil>;
308
214
  }
309
- const X = withSigilTyped(_X, 'X');
310
- type X = GetInstance<typeof X>;
311
-
312
- class _Y extends X {} // <-- This is allowed!
313
- const Y = withSigilTyped(_Y, 'Y');
314
- type Y = GetInstance<typeof Y>;
315
215
 
316
- const y = new Y(); // <-- Type here is any
216
+ const MyClass = withSigil(_MyClass, '@scope/package.MyClass');
217
+ type MyClass = InstanceType<typeof MyClass>;
317
218
  ```
318
219
 
319
- This is a known TypeScript limitation.
320
-
321
- ---
220
+ Note that you can't use `InstanceType` on `private` or `protected` classes.
322
221
 
323
- ### 2. Decorator pattern
324
-
325
- Inject brand directly in class body:
222
+ ### Inheritance example
326
223
 
327
224
  ```ts
328
- import { Sigil, WithSigil, UpdateSigilBrand } from '@vicin/sigil';
225
+ import { Sigil, WithSigil } from '@vicin/sigil';
329
226
 
330
- @WithSigil('X')
331
- class X extends Sigil {
332
- declare __SIGIL_BRAND__: UpdateSigilBrand<'X', Sigil>;
227
+ @WithSigil('@myorg/User')
228
+ class User extends Sigil {
229
+ declare [sigil]: ExtendSigil<'@myorg/User', Sigil>;
333
230
  }
334
231
 
335
- @WithSigil('Y')
336
- class Y extends X {
337
- declare __SIGIL_BRAND__: UpdateSigilBrand<'Y', X>;
232
+ @WithSigil('@myorg/Admin')
233
+ class Admin extends User {
234
+ declare [sigil]: ExtendSigil<'@myorg/Admin', User>;
338
235
  }
339
- ```
340
-
341
- No `_Class`/`Class` pattern, no `private constructor` issue, no type hacks and only one extra line, but our branding logic now lives in class body.
342
-
343
- #### Label Consistency
344
236
 
345
- Use typeof label for compile-time matching:
237
+ const admin = new Admin();
238
+ const user = new User();
346
239
 
347
- ```ts
348
- import { Sigil, WithSigil, UpdateSigilBrand } from '@vicin/sigil';
240
+ // Instanceof like behavior
241
+ console.log(Admin.isOfType(admin)); // true
242
+ console.log(Admin.isOfType(user)); // false
243
+ console.log(User.isOfType(admin)); // true
244
+ console.log(User.isOfType(user)); // true
349
245
 
350
- const label = 'X';
246
+ // Exact checks
247
+ console.log(Admin.isOfType(admin)); // true
248
+ console.log(Admin.isOfType(user)); // false
249
+ console.log(User.isOfType(user)); // true
250
+ console.log(User.isOfType(admin)); // false (Admin is child indeed but this checks for user specifically)
351
251
 
352
- @WithSigil(label)
353
- class X extends Sigil {
354
- declare __SIGIL_BRAND__: UpdateSigilBrand<typeof label, Sigil>;
355
- }
252
+ type test1 = Admin extends User ? true : false; // true
253
+ type test2 = User extends Admin ? true : false; // false
356
254
  ```
357
255
 
358
256
  ---
@@ -374,7 +272,6 @@ class X extends Sigil {
374
272
 
375
273
  - **HOFs:**
376
274
  - `withSigil(Class, label?, opts?)`
377
- - `withSigilTyped(Class, label?, opts?)`
378
275
 
379
276
  - **Helpers:**
380
277
  - `isSigilCtor(ctor)`
@@ -392,20 +289,17 @@ class X extends Sigil {
392
289
  - `ISigil<Label, ParentSigil?>`
393
290
  - `ISigilStatic<Label, ParentSigil?>`
394
291
  - `ISigilInstance<Label, ParentSigil?>`
395
- - `SigilBrandOf<T>`
396
- - `TypedSigil<SigilClass, Label>`
397
- - `GetInstance<T>`
398
- - `UpdateSigilBrand<Label, Base>`
292
+ - `SigilOf<T>`
293
+ - `ExtendSigil<Label, Parent>`
399
294
  - `SigilOptions`
400
295
 
401
296
  ### Key helpers (runtime)
402
297
 
403
298
  - `Sigil`: a minimal sigilified base class you can extend from.
404
299
  - `SigilError`: an `Error` class decorated with a `Sigil` so it can be identified at runtime.
405
- - `WithSigil(label)`: class decorator that attaches `Sigil` metadata at declaration time.
406
300
  - `Sigilify(Base, label?, opts?)`: mixin function that returns a new constructor with `Sigil` types and instance helpers.
301
+ - `WithSigil(label)`: class decorator that attaches `Sigil` metadata at declaration time.
407
302
  - `withSigil(Class, label?, opts?)`: HOF that validates and decorates an existing class constructor.
408
- - `withSigilTyped(Class, label?, opts?)`: like `withSigil` but narrows the TypeScript type to include brands.
409
303
  - `isSigilCtor(value)`: `true` if `value` is a `Sigil` constructor.
410
304
  - `isSigilInstance(value)`: `true` if `value` is an instance of a `Sigil` constructor.
411
305
  - `updateSigilOptions(opts)`: change global runtime options before `Sigil` decoration (e.g., `autofillLabels`).
@@ -417,11 +311,11 @@ When a constructor is decorated/sigilified it will expose the following **static
417
311
 
418
312
  - `SigilLabel` β€” the identity label string.
419
313
  - `SigilEffectiveLabel` β€” the human label string.
420
- - `SigilLabelLineage` β€” readonly array of labels representing parent β†’ child.
421
- - `SigilLabelSet` β€” readonly `Set<string>` for O(1) checks.
314
+ - `SigilLabelLineage` β€” readonly array of labels representing parent β†’ child for debugging.
315
+ - `SigilLabelSet` β€” readonly `Set<string>` for debugging.
422
316
  - `isSigilified(obj)` β€” runtime predicate that delegates to `isSigilInstance`.
423
- - `isOfType(other)` β€” O(1) membership test using `other`'s `__LABEL_SET__`.
424
- - `isOfTypeStrict(other)` β€” strict lineage comparison element-by-element.
317
+ - `isOfType(other)` β€” check if other is an instance of this constructor or its children.
318
+ - `isExactType(other) `β€” check if other is an instance exactly this constructor.
425
319
 
426
320
  Instances of sigilified classes expose instance helpers:
427
321
 
@@ -429,8 +323,8 @@ Instances of sigilified classes expose instance helpers:
429
323
  - `getSigilEffectiveLabel()` β€” returns the human label.
430
324
  - `getSigilLabelLineage()` β€” returns lineage array.
431
325
  - `getSigilLabelSet()` β€” returns readonly Set.
432
- - `isOfType(other)` β€” O(1) membership test using `other`'s `__LABEL_SET__`.
433
- - `isOfTypeStrict(other)` β€” strict lineage comparison element-by-element.
326
+ - `isOfType(other)` β€” check if other is an instance of the same class or its children as this.
327
+ - `isExactType(other) `β€” check if other is an instance exactly the same constructor.
434
328
 
435
329
  ---
436
330
 
@@ -467,7 +361,7 @@ class C extends B {}
467
361
 
468
362
  ## Strict mode
469
363
 
470
- If you want to inforce passing a label to every class defined in your codebase, you can set `autofillLabels` to `false` at the start of app:
364
+ If you want to enforce passing a label to every class defined in your codebase, you can set `autofillLabels` to `false` at the start of app:
471
365
 
472
366
  ```ts
473
367
  import { updateSigilOptions } from '@vicin/sigil';
@@ -479,20 +373,49 @@ Now if you forgot to pass a label error is thrown.
479
373
 
480
374
  ---
481
375
 
482
- ## Which pattern should I use?
376
+ ## Benchmarks
483
377
 
484
- - Want simplest setup? β†’ Extend `Sigil`
485
- - Want full nominal typing? β†’ Use HOF pattern
486
- - Want clean class bodies? β†’ Use HOF
487
- - Want fewer wrapper exports? β†’ Use Decorators
378
+ Sigil is built for **real-world performance**. Below are the latest micro-benchmark results (run on **Node.js v20.12.0**).
379
+ To run benchmarks on your machine fetch source code from [github](https://github.com/ZiadTaha62/sigil) and run `npm run bench` in your console.
488
380
 
489
- ---
381
+ ### 1. Runtime Type Checking
382
+
383
+ | Depth | `instanceof` (per op) | `isOfType` (ctor) | `isOfType` (instance) | `isExactType` (ctor) | `isExactType` (instance) |
384
+ | ----- | --------------------- | ----------------- | --------------------- | -------------------- | ------------------------ |
385
+ | 0 | 0.000010 ms | 0.000025 ms | **0.000010 ms** | 0.000027 ms | 0.000012 ms |
386
+ | 3 | 0.000032 ms | 0.000045 ms | **0.000027 ms** | 0.000038 ms | **0.000025 ms** |
387
+ | 5 | 0.000034 ms | 0.000046 ms | **0.000028 ms** | 0.000037 ms | **0.000026 ms** |
388
+ | 10 | 0.000044 ms | 0.000045 ms | **0.000029 ms** | 0.000038 ms | **0.000027 ms** |
389
+ | 15 | 0.000058 ms | 0.000063 ms | **0.000051 ms** | 0.000069 ms | **0.000053 ms** |
390
+
391
+ > **Key takeaway**:
392
+ > `isOfType` has **practically the same performance as native `instanceof`**, slightly **slower** on static calls and slightly **faster** on the instance side.
393
+ > `isExactType` adds only a tiny negligible cost and remains extremely fast even on deep hierarchies.
394
+
395
+ ### 2. Class Definition & Instance Creation
396
+
397
+ | Scenario | Definition (per class) | Instantiation (per instance) |
398
+ | ------------------------------- | ---------------------- | ---------------------------- |
399
+ | Empty plain class | 0.0122 ms | 0.00019 ms |
400
+ | Empty Sigil class | 0.0672 ms | 0.00059 ms |
401
+ | Small (5 props + 3 methods) | 0.0172 ms | 0.00327 ms |
402
+ | Large (15 props + 10 methods) | 0.0212 ms | 0.00922 ms |
403
+ | Large Sigil | 0.0780 ms | 0.01177 ms |
404
+ | Extended chain depth 5 – plain | 0.0897 ms | 0.01809 ms |
405
+ | Extended chain depth 5 – Sigil | 0.3978 ms | 0.02020 ms |
406
+ | Extended chain depth 10 – plain | 0.2042 ms | 0.05759 ms |
407
+ | Extended chain depth 10 – Sigil | 0.8127 ms | 0.06675 ms |
408
+
409
+ > **Key takeaways**:
410
+ >
411
+ > - Class definition is a **one-time cost** at module load time. Even at depth 10 the cost stays well under 1 ms per class.
412
+ > - Instance creation adds a small fixed overhead of ~0.4–0.6 Β΅s per object, which becomes completely negligible as your classes grow in size and complexity.
413
+
414
+ ### Bundle Size
490
415
 
491
- ## Troubleshooting & FAQ
416
+ **less than 1.5 KB** (minified + Brotli, including all dependencies)
492
417
 
493
- - **Dev Extension Errors:** Add labels or enable autofillLabels.
494
- - **Anonymous Class Errors:** Export untyped bases.
495
- - **Selective Labeling:** Use `autofillLabels: true` or empty `@WithSigil()` for auto-generation.
418
+ This makes Sigil one of the smallest full-featured solutions for nominal typing + reliable runtime identity.
496
419
 
497
420
  ---
498
421