@dereekb/util 13.16.0 → 13.17.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/eslint/package.json +2 -2
- package/fetch/package.json +2 -2
- package/package.json +1 -1
- package/src/lib/type.d.ts +45 -0
- package/test/package.json +2 -2
package/eslint/package.json
CHANGED
package/fetch/package.json
CHANGED
package/package.json
CHANGED
package/src/lib/type.d.ts
CHANGED
|
@@ -4,6 +4,51 @@ import { type Maybe } from './value/maybe.type';
|
|
|
4
4
|
* Boolean, string or number value.
|
|
5
5
|
*/
|
|
6
6
|
export type PrimativeValue = boolean | string | number;
|
|
7
|
+
/**
|
|
8
|
+
* Phantom key used to nominally brand a primitive type.
|
|
9
|
+
*
|
|
10
|
+
* Declared (never defined) so it exists only in the type system and carries no
|
|
11
|
+
* runtime cost. Two `Brand<number, A>` / `Brand<number, B>` types are distinct
|
|
12
|
+
* whenever `A !== B`, which is what gives branded ids/keys their nominal identity
|
|
13
|
+
* despite sharing the same underlying primitive at runtime.
|
|
14
|
+
*/
|
|
15
|
+
export declare const BRAND: unique symbol;
|
|
16
|
+
/**
|
|
17
|
+
* Nominally brands a primitive `TValue` with the compile-time-only tag `TBrand`.
|
|
18
|
+
*
|
|
19
|
+
* The brand is a zero-cost nominal type: the `[BRAND]` phantom key is erased at
|
|
20
|
+
* runtime, so a `Brand<number, 'UserId'>` is just a `number` once compiled, but
|
|
21
|
+
* the compiler refuses to mix it with a `Brand<number, 'PostId'>` or with a bare
|
|
22
|
+
* `number`. Use it to stop two structurally identical primitives (two id spaces,
|
|
23
|
+
* a raw count vs. a currency amount, ciphertext vs. plaintext, ...) from being
|
|
24
|
+
* accidentally interchanged.
|
|
25
|
+
*
|
|
26
|
+
* Branded values are minted at a trusted edge — a parser, a decoder, or an `as`
|
|
27
|
+
* assertion inside a constructor function — and then flow through the rest of the
|
|
28
|
+
* code as the branded type, so the "is this the right kind of value?" check is
|
|
29
|
+
* paid once rather than at every call site.
|
|
30
|
+
*
|
|
31
|
+
* @typeParam TValue - The underlying runtime representation (e.g. `number`, `string`).
|
|
32
|
+
* @typeParam TBrand - A unique string tag distinguishing this brand from others.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* type UserId = Brand<number, 'UserId'>;
|
|
37
|
+
* type PostId = Brand<number, 'PostId'>;
|
|
38
|
+
*
|
|
39
|
+
* function loadUser(id: UserId): User { ... }
|
|
40
|
+
*
|
|
41
|
+
* const userId = 10 as UserId;
|
|
42
|
+
* const postId = 10 as PostId;
|
|
43
|
+
*
|
|
44
|
+
* loadUser(userId); // ok
|
|
45
|
+
* loadUser(postId); // compile error: PostId is not assignable to UserId
|
|
46
|
+
* loadUser(10); // compile error: number is not assignable to UserId
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export type Brand<TValue, TBrand extends string> = TValue & {
|
|
50
|
+
readonly [BRAND]: TBrand;
|
|
51
|
+
};
|
|
7
52
|
/**
|
|
8
53
|
* Open-ended union of known string literals `T` plus an arbitrary string fallback.
|
|
9
54
|
*
|