@prisma-next/utils 0.11.0-dev.13 → 0.11.0-dev.15
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/dist/casts-D2-X_DNw.mjs +82 -0
- package/dist/casts-D2-X_DNw.mjs.map +1 -0
- package/dist/casts.d.mts +77 -0
- package/dist/casts.d.mts.map +1 -0
- package/dist/casts.mjs +2 -0
- package/dist/{defined-BYcWqtXq.mjs → defined-BnXRnErx.mjs} +1 -1
- package/dist/{defined-BYcWqtXq.mjs.map → defined-BnXRnErx.mjs.map} +1 -1
- package/dist/defined.mjs +1 -1
- package/dist/redact-db-url.mjs +1 -1
- package/dist/result.d.mts.map +1 -1
- package/dist/result.mjs +14 -2
- package/dist/result.mjs.map +1 -1
- package/package.json +4 -3
- package/src/casts.ts +80 -0
- package/src/exports/casts.ts +1 -0
- package/src/result.ts +10 -6
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
//#region src/casts.ts
|
|
2
|
+
/**
|
|
3
|
+
* **Last-resort escape hatch for unsafe type assertions. Not a sanctioned tool to reach for.**
|
|
4
|
+
*
|
|
5
|
+
* Before reaching for `blindCast`, **rewrite the surrounding code so the cast becomes
|
|
6
|
+
* unnecessary**: tighten an input type, add a runtime check that narrows via a type
|
|
7
|
+
* predicate, restructure a generic so the compiler can see the relationship you're
|
|
8
|
+
* asserting, or use {@link castAs} when the value already satisfies the target type.
|
|
9
|
+
* Only when no rewrite is feasible does `blindCast` become the right answer — and at
|
|
10
|
+
* that point, the `Reason` literal you supply must articulate the compromise in
|
|
11
|
+
* language a reviewer can evaluate.
|
|
12
|
+
*
|
|
13
|
+
* The reviewer **will** validate the `Reason`. If it doesn't hold up under scrutiny,
|
|
14
|
+
* that is not a signal to soften the reason; it is a signal to go back and solve the
|
|
15
|
+
* underlying type-system problem properly. An unconvincing justification is rework,
|
|
16
|
+
* not a free pass.
|
|
17
|
+
*
|
|
18
|
+
* `blindCast` is the auditable form of `as Foo` / `as unknown as Foo`: it bypasses
|
|
19
|
+
* the compiler's checks (the input type is `unknown`, the output type is whatever the
|
|
20
|
+
* caller asks for), but it forces the unsafety to be named at the call site instead of
|
|
21
|
+
* smuggled in via a bare `as`. The `Reason` type parameter exists only at compile
|
|
22
|
+
* time — it is not present in the emitted JavaScript — but it is grep-able and
|
|
23
|
+
* visible to future readers.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const stringValue = blindCast<
|
|
28
|
+
* string,
|
|
29
|
+
* "JSON.parse returns `unknown`; this field is documented to be a string in the API contract"
|
|
30
|
+
* >(parsed[key]);
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @typeParam TargetType - The type the caller is asserting the input has.
|
|
34
|
+
* @typeParam _Reason - A string literal describing why bypassing the type system is necessary here.
|
|
35
|
+
* Only meaningful at compile time. The reviewer evaluates whether it justifies the unsafety.
|
|
36
|
+
*/
|
|
37
|
+
function blindCast(input) {
|
|
38
|
+
return input;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Type-checked, runtime pass-through alternative to a bare `as Type` cast.
|
|
42
|
+
*
|
|
43
|
+
* Use `castAs` when the value already satisfies the target type but you want to make
|
|
44
|
+
* the type assertion explicit at the call site — for example, when an inferred type is
|
|
45
|
+
* wider than the type you want to publish, or when a literal object should be tagged
|
|
46
|
+
* with its nominal interface. Unlike {@link blindCast}, the compiler still checks that
|
|
47
|
+
* the value is assignable to the target type, so this helper cannot smuggle in an
|
|
48
|
+
* unsafe assertion.
|
|
49
|
+
*
|
|
50
|
+
* `castAs` exists alongside `blindCast` so authors pick the right name at the call
|
|
51
|
+
* site: a `castAs` is type-checked and benign; a `blindCast` is the unsafe escape
|
|
52
|
+
* hatch. The split makes review faster — readers know which casts to scrutinize and
|
|
53
|
+
* which are pure annotations.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* interface FancyObject {
|
|
58
|
+
* key: string;
|
|
59
|
+
* keyTwo: {
|
|
60
|
+
* subKey: string;
|
|
61
|
+
* subKeyTwo: number;
|
|
62
|
+
* };
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* const typedObject = castAs<FancyObject>({
|
|
66
|
+
* key: 'Chookede',
|
|
67
|
+
* keyTwo: {
|
|
68
|
+
* subKey: 'Choookeeeee',
|
|
69
|
+
* subKeyTwo: 2,
|
|
70
|
+
* },
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @typeParam Type - The type to constrain and tag the value with. The value must be assignable to `Type`.
|
|
75
|
+
*/
|
|
76
|
+
function castAs(value) {
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
export { castAs as n, blindCast as t };
|
|
81
|
+
|
|
82
|
+
//# sourceMappingURL=casts-D2-X_DNw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"casts-D2-X_DNw.mjs","names":["x"],"sources":["../src/casts.ts"],"sourcesContent":["/**\n * **Last-resort escape hatch for unsafe type assertions. Not a sanctioned tool to reach for.**\n *\n * Before reaching for `blindCast`, **rewrite the surrounding code so the cast becomes\n * unnecessary**: tighten an input type, add a runtime check that narrows via a type\n * predicate, restructure a generic so the compiler can see the relationship you're\n * asserting, or use {@link castAs} when the value already satisfies the target type.\n * Only when no rewrite is feasible does `blindCast` become the right answer — and at\n * that point, the `Reason` literal you supply must articulate the compromise in\n * language a reviewer can evaluate.\n *\n * The reviewer **will** validate the `Reason`. If it doesn't hold up under scrutiny,\n * that is not a signal to soften the reason; it is a signal to go back and solve the\n * underlying type-system problem properly. An unconvincing justification is rework,\n * not a free pass.\n *\n * `blindCast` is the auditable form of `as Foo` / `as unknown as Foo`: it bypasses\n * the compiler's checks (the input type is `unknown`, the output type is whatever the\n * caller asks for), but it forces the unsafety to be named at the call site instead of\n * smuggled in via a bare `as`. The `Reason` type parameter exists only at compile\n * time — it is not present in the emitted JavaScript — but it is grep-able and\n * visible to future readers.\n *\n * @example\n * ```typescript\n * const stringValue = blindCast<\n * string,\n * \"JSON.parse returns `unknown`; this field is documented to be a string in the API contract\"\n * >(parsed[key]);\n * ```\n *\n * @typeParam TargetType - The type the caller is asserting the input has.\n * @typeParam _Reason - A string literal describing why bypassing the type system is necessary here.\n * Only meaningful at compile time. The reviewer evaluates whether it justifies the unsafety.\n */\nexport function blindCast<TargetType, _Reason extends string>(input: unknown): TargetType {\n // biome-ignore lint/suspicious/noExplicitAny: this helper is the single canonical escape hatch for type-unsafe casts in the codebase; the `any` is hyper-local, the unsafety is made explicit at every call site via the call's own `Reason` literal, and the reviewer evaluates whether that justification holds\n const x: any = input;\n return x;\n}\n\n/**\n * Type-checked, runtime pass-through alternative to a bare `as Type` cast.\n *\n * Use `castAs` when the value already satisfies the target type but you want to make\n * the type assertion explicit at the call site — for example, when an inferred type is\n * wider than the type you want to publish, or when a literal object should be tagged\n * with its nominal interface. Unlike {@link blindCast}, the compiler still checks that\n * the value is assignable to the target type, so this helper cannot smuggle in an\n * unsafe assertion.\n *\n * `castAs` exists alongside `blindCast` so authors pick the right name at the call\n * site: a `castAs` is type-checked and benign; a `blindCast` is the unsafe escape\n * hatch. The split makes review faster — readers know which casts to scrutinize and\n * which are pure annotations.\n *\n * @example\n * ```typescript\n * interface FancyObject {\n * key: string;\n * keyTwo: {\n * subKey: string;\n * subKeyTwo: number;\n * };\n * }\n *\n * const typedObject = castAs<FancyObject>({\n * key: 'Chookede',\n * keyTwo: {\n * subKey: 'Choookeeeee',\n * subKeyTwo: 2,\n * },\n * });\n * ```\n *\n * @typeParam Type - The type to constrain and tag the value with. The value must be assignable to `Type`.\n */\nexport function castAs<Type>(value: Type): Type {\n return value;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCA,SAAgB,UAA8C,OAA4B;CAGxF,OAAOA;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,OAAa,OAAmB;CAC9C,OAAO;AACT"}
|
package/dist/casts.d.mts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/casts.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* **Last-resort escape hatch for unsafe type assertions. Not a sanctioned tool to reach for.**
|
|
4
|
+
*
|
|
5
|
+
* Before reaching for `blindCast`, **rewrite the surrounding code so the cast becomes
|
|
6
|
+
* unnecessary**: tighten an input type, add a runtime check that narrows via a type
|
|
7
|
+
* predicate, restructure a generic so the compiler can see the relationship you're
|
|
8
|
+
* asserting, or use {@link castAs} when the value already satisfies the target type.
|
|
9
|
+
* Only when no rewrite is feasible does `blindCast` become the right answer — and at
|
|
10
|
+
* that point, the `Reason` literal you supply must articulate the compromise in
|
|
11
|
+
* language a reviewer can evaluate.
|
|
12
|
+
*
|
|
13
|
+
* The reviewer **will** validate the `Reason`. If it doesn't hold up under scrutiny,
|
|
14
|
+
* that is not a signal to soften the reason; it is a signal to go back and solve the
|
|
15
|
+
* underlying type-system problem properly. An unconvincing justification is rework,
|
|
16
|
+
* not a free pass.
|
|
17
|
+
*
|
|
18
|
+
* `blindCast` is the auditable form of `as Foo` / `as unknown as Foo`: it bypasses
|
|
19
|
+
* the compiler's checks (the input type is `unknown`, the output type is whatever the
|
|
20
|
+
* caller asks for), but it forces the unsafety to be named at the call site instead of
|
|
21
|
+
* smuggled in via a bare `as`. The `Reason` type parameter exists only at compile
|
|
22
|
+
* time — it is not present in the emitted JavaScript — but it is grep-able and
|
|
23
|
+
* visible to future readers.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const stringValue = blindCast<
|
|
28
|
+
* string,
|
|
29
|
+
* "JSON.parse returns `unknown`; this field is documented to be a string in the API contract"
|
|
30
|
+
* >(parsed[key]);
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @typeParam TargetType - The type the caller is asserting the input has.
|
|
34
|
+
* @typeParam _Reason - A string literal describing why bypassing the type system is necessary here.
|
|
35
|
+
* Only meaningful at compile time. The reviewer evaluates whether it justifies the unsafety.
|
|
36
|
+
*/
|
|
37
|
+
declare function blindCast<TargetType, _Reason extends string>(input: unknown): TargetType;
|
|
38
|
+
/**
|
|
39
|
+
* Type-checked, runtime pass-through alternative to a bare `as Type` cast.
|
|
40
|
+
*
|
|
41
|
+
* Use `castAs` when the value already satisfies the target type but you want to make
|
|
42
|
+
* the type assertion explicit at the call site — for example, when an inferred type is
|
|
43
|
+
* wider than the type you want to publish, or when a literal object should be tagged
|
|
44
|
+
* with its nominal interface. Unlike {@link blindCast}, the compiler still checks that
|
|
45
|
+
* the value is assignable to the target type, so this helper cannot smuggle in an
|
|
46
|
+
* unsafe assertion.
|
|
47
|
+
*
|
|
48
|
+
* `castAs` exists alongside `blindCast` so authors pick the right name at the call
|
|
49
|
+
* site: a `castAs` is type-checked and benign; a `blindCast` is the unsafe escape
|
|
50
|
+
* hatch. The split makes review faster — readers know which casts to scrutinize and
|
|
51
|
+
* which are pure annotations.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* interface FancyObject {
|
|
56
|
+
* key: string;
|
|
57
|
+
* keyTwo: {
|
|
58
|
+
* subKey: string;
|
|
59
|
+
* subKeyTwo: number;
|
|
60
|
+
* };
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* const typedObject = castAs<FancyObject>({
|
|
64
|
+
* key: 'Chookede',
|
|
65
|
+
* keyTwo: {
|
|
66
|
+
* subKey: 'Choookeeeee',
|
|
67
|
+
* subKeyTwo: 2,
|
|
68
|
+
* },
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* @typeParam Type - The type to constrain and tag the value with. The value must be assignable to `Type`.
|
|
73
|
+
*/
|
|
74
|
+
declare function castAs<Type>(value: Type): Type;
|
|
75
|
+
//#endregion
|
|
76
|
+
export { blindCast, castAs };
|
|
77
|
+
//# sourceMappingURL=casts.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"casts.d.mts","names":[],"sources":["../src/casts.ts"],"mappings":";;AAmCA;;;;;;;;;AAAyF;AA0CzF;;;;;;;;;AAA+C;;;;;;;;;;;;;;;iBA1C/B,SAAA,oCAAA,CAA8C,KAAA,YAAiB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0CzE,MAAA,MAAA,CAAa,KAAA,EAAO,IAAA,GAAO,IAAI"}
|
package/dist/casts.mjs
ADDED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defined-
|
|
1
|
+
{"version":3,"file":"defined-BnXRnErx.mjs","names":[],"sources":["../src/defined.ts"],"sourcesContent":["/**\n * Returns an object with the key/value if value is defined, otherwise an empty object.\n *\n * Use with spread to conditionally include optional properties while satisfying\n * exactOptionalPropertyTypes. This is explicit about which properties are optional\n * and won't inadvertently strip other undefined values.\n *\n * @example\n * ```typescript\n * // Instead of:\n * const obj = {\n * required: 'value',\n * ...(optional ? { optional } : {}),\n * };\n *\n * // Use:\n * const obj = {\n * required: 'value',\n * ...ifDefined('optional', optional),\n * };\n * ```\n */\nexport function ifDefined<K extends string, V>(\n key: K,\n value: V | undefined,\n): Record<never, never> | { [P in K]: V } {\n return value !== undefined ? ({ [key]: value } as { [P in K]: V }) : {};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,UACd,KACA,OACwC;CACxC,OAAO,UAAU,KAAA,IAAa,GAAG,MAAM,MAAM,IAAwB,CAAC;AACxE"}
|
package/dist/defined.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ifDefined } from "./defined-
|
|
1
|
+
import { t as ifDefined } from "./defined-BnXRnErx.mjs";
|
|
2
2
|
export { ifDefined };
|
package/dist/redact-db-url.mjs
CHANGED
package/dist/result.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.d.mts","names":[],"sources":["../src/result.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"result.d.mts","names":[],"sources":["../src/result.ts"],"mappings":";;AAiBA;;;;;;;;;;;;AAIa;UAJI,EAAA;EAAA,SACN,EAAA;EAAA,SACA,KAAA,EAAO,CAAA;EAChB,QAAA,IAAY,CAAC;EACb,WAAA;AAAA;;;;UAMe,KAAA;EAAA,SACN,EAAA;EAAA,SACA,OAAA,EAAS,CAAA;EAClB,QAAA;EACA,WAAA,IAAe,CAAC;AAAA;;;;;;;KASN,MAAA,SAAe,EAAA,CAAG,CAAA,IAAK,KAAA,CAAM,CAAA;;;;iBAkFzB,EAAA,GAAA,CAAM,KAAA,EAAO,CAAA,GAAI,EAAA,CAAG,CAAA;;;;iBAOpB,KAAA,GAAA,CAAS,OAAA,EAAS,CAAA,GAAI,KAAA,CAAM,CAAA;AAP5C;;;;AAAA,iBAqBgB,MAAA,CAAA,GAAU,EAAE"}
|
package/dist/result.mjs
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
+
import { t as blindCast } from "./casts-D2-X_DNw.mjs";
|
|
1
2
|
//#region src/result.ts
|
|
2
3
|
/**
|
|
4
|
+
* Generic Result type for representing success or failure outcomes.
|
|
5
|
+
*
|
|
6
|
+
* This is the standard way to return "expected failures" as values rather than
|
|
7
|
+
* throwing exceptions. See docs/Error Handling.md for the full taxonomy.
|
|
8
|
+
*
|
|
9
|
+
* Naming rationale:
|
|
10
|
+
* - `Ok<T>` / `NotOk<F>` mirror the `ok: true/false` discriminator
|
|
11
|
+
* - `NotOk` avoids collision with domain types like "Failure" or "Error"
|
|
12
|
+
* - `failure` property distinguishes from JS Error semantics
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
3
15
|
* Result class that implements both Ok and NotOk variants.
|
|
4
16
|
*/
|
|
5
17
|
var ResultImpl = class ResultImpl {
|
|
@@ -24,13 +36,13 @@ var ResultImpl = class ResultImpl {
|
|
|
24
36
|
* Creates a successful result.
|
|
25
37
|
*/
|
|
26
38
|
static ok(value) {
|
|
27
|
-
return new ResultImpl(true, value);
|
|
39
|
+
return blindCast(new ResultImpl(true, value));
|
|
28
40
|
}
|
|
29
41
|
/**
|
|
30
42
|
* Creates an unsuccessful result.
|
|
31
43
|
*/
|
|
32
44
|
static notOk(failure) {
|
|
33
|
-
return new ResultImpl(false, failure);
|
|
45
|
+
return blindCast(new ResultImpl(false, failure));
|
|
34
46
|
}
|
|
35
47
|
/**
|
|
36
48
|
* Asserts that this result is Ok and returns the value.
|
package/dist/result.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.mjs","names":[],"sources":["../src/result.ts"],"sourcesContent":["/**\n * Generic Result type for representing success or failure outcomes.\n *\n * This is the standard way to return \"expected failures\" as values rather than\n * throwing exceptions. See docs/Error Handling.md for the full taxonomy.\n *\n * Naming rationale:\n * - `Ok<T>` / `NotOk<F>` mirror the `ok: true/false` discriminator\n * - `NotOk` avoids collision with domain types like \"Failure\" or \"Error\"\n * - `failure` property distinguishes from JS Error semantics\n */\n\n/**\n * Represents a successful result containing a value.\n */\nexport interface Ok<T> {\n readonly ok: true;\n readonly value: T;\n assertOk(): T;\n assertNotOk(): never;\n}\n\n/**\n * Represents an unsuccessful result containing failure details.\n */\nexport interface NotOk<F> {\n readonly ok: false;\n readonly failure: F;\n assertOk(): never;\n assertNotOk(): F;\n}\n\n/**\n * A discriminated union representing either success (Ok) or failure (NotOk).\n *\n * @typeParam T - The success value type\n * @typeParam F - The failure details type\n */\nexport type Result<T, F> = Ok<T> | NotOk<F>;\n\n/**\n * Result class that implements both Ok and NotOk variants.\n */\nclass ResultImpl<T, F> {\n readonly ok: boolean;\n private readonly _value?: T;\n private readonly _failure?: F;\n\n private constructor(ok: boolean, valueOrFailure: T | F) {\n this.ok = ok;\n if (ok) {\n this._value = valueOrFailure as T;\n } else {\n this._failure = valueOrFailure as F;\n }\n Object.freeze(this);\n }\n\n get value(): T {\n if (!this.ok) {\n throw new Error('Cannot access value on NotOk result');\n }\n // biome-ignore lint/style/noNonNullAssertion: must be present if ok is true\n return this._value!;\n }\n\n get failure(): F {\n if (this.ok) {\n throw new Error('Cannot access failure on Ok result');\n }\n // biome-ignore lint/style/noNonNullAssertion: must be present if ok is false\n return this._failure!;\n }\n\n /**\n * Creates a successful result.\n */\n static ok<T, F = never>(value: T): Ok<T> {\n
|
|
1
|
+
{"version":3,"file":"result.mjs","names":[],"sources":["../src/result.ts"],"sourcesContent":["/**\n * Generic Result type for representing success or failure outcomes.\n *\n * This is the standard way to return \"expected failures\" as values rather than\n * throwing exceptions. See docs/Error Handling.md for the full taxonomy.\n *\n * Naming rationale:\n * - `Ok<T>` / `NotOk<F>` mirror the `ok: true/false` discriminator\n * - `NotOk` avoids collision with domain types like \"Failure\" or \"Error\"\n * - `failure` property distinguishes from JS Error semantics\n */\n\nimport { blindCast } from './casts';\n\n/**\n * Represents a successful result containing a value.\n */\nexport interface Ok<T> {\n readonly ok: true;\n readonly value: T;\n assertOk(): T;\n assertNotOk(): never;\n}\n\n/**\n * Represents an unsuccessful result containing failure details.\n */\nexport interface NotOk<F> {\n readonly ok: false;\n readonly failure: F;\n assertOk(): never;\n assertNotOk(): F;\n}\n\n/**\n * A discriminated union representing either success (Ok) or failure (NotOk).\n *\n * @typeParam T - The success value type\n * @typeParam F - The failure details type\n */\nexport type Result<T, F> = Ok<T> | NotOk<F>;\n\n/**\n * Result class that implements both Ok and NotOk variants.\n */\nclass ResultImpl<T, F> {\n readonly ok: boolean;\n private readonly _value?: T;\n private readonly _failure?: F;\n\n private constructor(ok: boolean, valueOrFailure: T | F) {\n this.ok = ok;\n if (ok) {\n this._value = valueOrFailure as T;\n } else {\n this._failure = valueOrFailure as F;\n }\n Object.freeze(this);\n }\n\n get value(): T {\n if (!this.ok) {\n throw new Error('Cannot access value on NotOk result');\n }\n // biome-ignore lint/style/noNonNullAssertion: must be present if ok is true\n return this._value!;\n }\n\n get failure(): F {\n if (this.ok) {\n throw new Error('Cannot access failure on Ok result');\n }\n // biome-ignore lint/style/noNonNullAssertion: must be present if ok is false\n return this._failure!;\n }\n\n /**\n * Creates a successful result.\n */\n static ok<T, F = never>(value: T): Ok<T> {\n return blindCast<\n Ok<T>,\n 'ResultImpl is the single implementation of the Result discriminated union; TypeScript cannot express discriminated return types for a single class. ok=true guarantees this is an Ok<T> at runtime.'\n >(new ResultImpl<T, F>(true, value));\n }\n\n /**\n * Creates an unsuccessful result.\n */\n static notOk<T = never, F = unknown>(failure: F): NotOk<F> {\n return blindCast<\n NotOk<F>,\n 'ResultImpl is the single implementation of the Result discriminated union; TypeScript cannot express discriminated return types for a single class. ok=false guarantees this is a NotOk<F> at runtime.'\n >(new ResultImpl<T, F>(false, failure));\n }\n\n /**\n * Asserts that this result is Ok and returns the value.\n * Throws if the result is NotOk.\n */\n assertOk(this: Result<T, F>): T {\n if (!this.ok) {\n throw new Error('Expected Ok result but got NotOk');\n }\n return this.value;\n }\n\n /**\n * Asserts that this result is NotOk and returns the failure.\n * Throws if the result is Ok.\n */\n assertNotOk(this: Result<T, F>): F {\n if (this.ok) {\n throw new Error('Expected NotOk result but got Ok');\n }\n return this.failure;\n }\n}\n\n/**\n * Creates a successful result.\n */\nexport function ok<T>(value: T): Ok<T> {\n return ResultImpl.ok(value);\n}\n\n/**\n * Creates an unsuccessful result.\n */\nexport function notOk<F>(failure: F): NotOk<F> {\n return ResultImpl.notOk(failure);\n}\n\n/**\n * Singleton for void success results.\n * Use this for validation checks that don't produce a value.\n */\nconst OK_VOID: Ok<void> = ResultImpl.ok<void>(undefined);\n\n/**\n * Returns a successful void result.\n * Use this for validation checks that don't produce a value.\n */\nexport function okVoid(): Ok<void> {\n return OK_VOID;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA6CA,IAAM,aAAN,MAAM,WAAiB;CACrB;CACA;CACA;CAEA,YAAoB,IAAa,gBAAuB;EACtD,KAAK,KAAK;EACV,IAAI,IACF,KAAK,SAAS;OAEd,KAAK,WAAW;EAElB,OAAO,OAAO,IAAI;CACpB;CAEA,IAAI,QAAW;EACb,IAAI,CAAC,KAAK,IACR,MAAM,IAAI,MAAM,qCAAqC;EAGvD,OAAO,KAAK;CACd;CAEA,IAAI,UAAa;EACf,IAAI,KAAK,IACP,MAAM,IAAI,MAAM,oCAAoC;EAGtD,OAAO,KAAK;CACd;;;;CAKA,OAAO,GAAiB,OAAiB;EACvC,OAAO,UAGL,IAAI,WAAiB,MAAM,KAAK,CAAC;CACrC;;;;CAKA,OAAO,MAA8B,SAAsB;EACzD,OAAO,UAGL,IAAI,WAAiB,OAAO,OAAO,CAAC;CACxC;;;;;CAMA,WAAgC;EAC9B,IAAI,CAAC,KAAK,IACR,MAAM,IAAI,MAAM,kCAAkC;EAEpD,OAAO,KAAK;CACd;;;;;CAMA,cAAmC;EACjC,IAAI,KAAK,IACP,MAAM,IAAI,MAAM,kCAAkC;EAEpD,OAAO,KAAK;CACd;AACF;;;;AAKA,SAAgB,GAAM,OAAiB;CACrC,OAAO,WAAW,GAAG,KAAK;AAC5B;;;;AAKA,SAAgB,MAAS,SAAsB;CAC7C,OAAO,WAAW,MAAM,OAAO;AACjC;;;;;AAMA,MAAM,UAAoB,WAAW,GAAS,KAAA,CAAS;;;;;AAMvD,SAAgB,SAAmB;CACjC,OAAO;AACT"}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/utils",
|
|
3
|
-
"version": "0.11.0-dev.
|
|
3
|
+
"version": "0.11.0-dev.15",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"description": "Shared utility functions for Prisma Next",
|
|
8
8
|
"devDependencies": {
|
|
9
|
-
"@prisma-next/tsconfig": "0.11.0-dev.
|
|
10
|
-
"@prisma-next/tsdown": "0.11.0-dev.
|
|
9
|
+
"@prisma-next/tsconfig": "0.11.0-dev.15",
|
|
10
|
+
"@prisma-next/tsdown": "0.11.0-dev.15",
|
|
11
11
|
"tsdown": "0.22.0",
|
|
12
12
|
"typescript": "5.9.3",
|
|
13
13
|
"vitest": "4.1.6"
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"./array-equal": "./dist/array-equal.mjs",
|
|
25
25
|
"./assertions": "./dist/assertions.mjs",
|
|
26
26
|
"./canonical-stringify": "./dist/canonical-stringify.mjs",
|
|
27
|
+
"./casts": "./dist/casts.mjs",
|
|
27
28
|
"./defined": "./dist/defined.mjs",
|
|
28
29
|
"./hash-content": "./dist/hash-content.mjs",
|
|
29
30
|
"./json": "./dist/json.mjs",
|
package/src/casts.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Last-resort escape hatch for unsafe type assertions. Not a sanctioned tool to reach for.**
|
|
3
|
+
*
|
|
4
|
+
* Before reaching for `blindCast`, **rewrite the surrounding code so the cast becomes
|
|
5
|
+
* unnecessary**: tighten an input type, add a runtime check that narrows via a type
|
|
6
|
+
* predicate, restructure a generic so the compiler can see the relationship you're
|
|
7
|
+
* asserting, or use {@link castAs} when the value already satisfies the target type.
|
|
8
|
+
* Only when no rewrite is feasible does `blindCast` become the right answer — and at
|
|
9
|
+
* that point, the `Reason` literal you supply must articulate the compromise in
|
|
10
|
+
* language a reviewer can evaluate.
|
|
11
|
+
*
|
|
12
|
+
* The reviewer **will** validate the `Reason`. If it doesn't hold up under scrutiny,
|
|
13
|
+
* that is not a signal to soften the reason; it is a signal to go back and solve the
|
|
14
|
+
* underlying type-system problem properly. An unconvincing justification is rework,
|
|
15
|
+
* not a free pass.
|
|
16
|
+
*
|
|
17
|
+
* `blindCast` is the auditable form of `as Foo` / `as unknown as Foo`: it bypasses
|
|
18
|
+
* the compiler's checks (the input type is `unknown`, the output type is whatever the
|
|
19
|
+
* caller asks for), but it forces the unsafety to be named at the call site instead of
|
|
20
|
+
* smuggled in via a bare `as`. The `Reason` type parameter exists only at compile
|
|
21
|
+
* time — it is not present in the emitted JavaScript — but it is grep-able and
|
|
22
|
+
* visible to future readers.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const stringValue = blindCast<
|
|
27
|
+
* string,
|
|
28
|
+
* "JSON.parse returns `unknown`; this field is documented to be a string in the API contract"
|
|
29
|
+
* >(parsed[key]);
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @typeParam TargetType - The type the caller is asserting the input has.
|
|
33
|
+
* @typeParam _Reason - A string literal describing why bypassing the type system is necessary here.
|
|
34
|
+
* Only meaningful at compile time. The reviewer evaluates whether it justifies the unsafety.
|
|
35
|
+
*/
|
|
36
|
+
export function blindCast<TargetType, _Reason extends string>(input: unknown): TargetType {
|
|
37
|
+
// biome-ignore lint/suspicious/noExplicitAny: this helper is the single canonical escape hatch for type-unsafe casts in the codebase; the `any` is hyper-local, the unsafety is made explicit at every call site via the call's own `Reason` literal, and the reviewer evaluates whether that justification holds
|
|
38
|
+
const x: any = input;
|
|
39
|
+
return x;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Type-checked, runtime pass-through alternative to a bare `as Type` cast.
|
|
44
|
+
*
|
|
45
|
+
* Use `castAs` when the value already satisfies the target type but you want to make
|
|
46
|
+
* the type assertion explicit at the call site — for example, when an inferred type is
|
|
47
|
+
* wider than the type you want to publish, or when a literal object should be tagged
|
|
48
|
+
* with its nominal interface. Unlike {@link blindCast}, the compiler still checks that
|
|
49
|
+
* the value is assignable to the target type, so this helper cannot smuggle in an
|
|
50
|
+
* unsafe assertion.
|
|
51
|
+
*
|
|
52
|
+
* `castAs` exists alongside `blindCast` so authors pick the right name at the call
|
|
53
|
+
* site: a `castAs` is type-checked and benign; a `blindCast` is the unsafe escape
|
|
54
|
+
* hatch. The split makes review faster — readers know which casts to scrutinize and
|
|
55
|
+
* which are pure annotations.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* interface FancyObject {
|
|
60
|
+
* key: string;
|
|
61
|
+
* keyTwo: {
|
|
62
|
+
* subKey: string;
|
|
63
|
+
* subKeyTwo: number;
|
|
64
|
+
* };
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* const typedObject = castAs<FancyObject>({
|
|
68
|
+
* key: 'Chookede',
|
|
69
|
+
* keyTwo: {
|
|
70
|
+
* subKey: 'Choookeeeee',
|
|
71
|
+
* subKeyTwo: 2,
|
|
72
|
+
* },
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @typeParam Type - The type to constrain and tag the value with. The value must be assignable to `Type`.
|
|
77
|
+
*/
|
|
78
|
+
export function castAs<Type>(value: Type): Type {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { blindCast, castAs } from '../casts';
|
package/src/result.ts
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* - `failure` property distinguishes from JS Error semantics
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { blindCast } from './casts';
|
|
14
|
+
|
|
13
15
|
/**
|
|
14
16
|
* Represents a successful result containing a value.
|
|
15
17
|
*/
|
|
@@ -76,18 +78,20 @@ class ResultImpl<T, F> {
|
|
|
76
78
|
* Creates a successful result.
|
|
77
79
|
*/
|
|
78
80
|
static ok<T, F = never>(value: T): Ok<T> {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
return blindCast<
|
|
82
|
+
Ok<T>,
|
|
83
|
+
'ResultImpl is the single implementation of the Result discriminated union; TypeScript cannot express discriminated return types for a single class. ok=true guarantees this is an Ok<T> at runtime.'
|
|
84
|
+
>(new ResultImpl<T, F>(true, value));
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
/**
|
|
85
88
|
* Creates an unsuccessful result.
|
|
86
89
|
*/
|
|
87
90
|
static notOk<T = never, F = unknown>(failure: F): NotOk<F> {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
return blindCast<
|
|
92
|
+
NotOk<F>,
|
|
93
|
+
'ResultImpl is the single implementation of the Result discriminated union; TypeScript cannot express discriminated return types for a single class. ok=false guarantees this is a NotOk<F> at runtime.'
|
|
94
|
+
>(new ResultImpl<T, F>(false, failure));
|
|
91
95
|
}
|
|
92
96
|
|
|
93
97
|
/**
|