kind-adt 0.1.1 → 0.1.3

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/README.md CHANGED
@@ -48,13 +48,14 @@ function safeDivide(n: number, d: number) {
48
48
  match(safeDivide(42, 2), {
49
49
  Some: (n) => console.log("Result:", n),
50
50
  None: () => console.log("Division by zero!"),
51
- });
51
+ });
52
52
  ```
53
53
 
54
54
  ## Features
55
55
 
56
56
  - _One_ type to define your **A**lgebraic **D**ata **T**ype (`Data`).
57
57
  - _One_ function to create **constructors**, **deconstructors**, **type guards** and **pattern matching function** for your ADT with **type safety** (`make`).
58
+ - Support for **functional pipelines** with a [`.pipe()` method](#functional-pipelines-with-pipe) on all ADTs.
58
59
  - [**Readable type signatures**](#provide-more-readable-type-signatures) for your ADT with _labeled tuples_.
59
60
  - [**Recursive ADTs**](#recursive-adts) with ease.
60
61
  - Tiny footprint (~1kB minzipped).
@@ -197,6 +198,8 @@ pipe(
197
198
  ); // => 84
198
199
  ```
199
200
 
201
+ See also the [functional pipelines with `.pipe()`](#functional-pipelines-with-pipe) section for details on kind-adt’s built-in alternative to external pipe utilities.
202
+
200
203
  Note that `ADT.match` requires the return type of each case to be the same. To allow different return types, you can use the `ADT.matchW` function, where the `W` suffix stands for _wider_. `ADT.matchW` can be used the same way as `ADT.match`, supporting both curried and non-curried overloads.
201
204
 
202
205
  <div align="right">
@@ -250,6 +253,60 @@ type None = Extract<Option<unknown>, Tagged<"None">>;
250
253
  // }
251
254
  ```
252
255
 
256
+ ### Functional pipelines with `.pipe()`
257
+
258
+ Every ADT in kind-adt supports a `.pipe()` method, allowing for a more functional and fluent style of programming similar to libraries like [Effect](https://github.com/Effect-TS/effect) or [RxJS](https://rxjs.dev/api/index/function/pipe).
259
+
260
+ ```typescript
261
+ import { type Data, make } from "kind-adt";
262
+ import type { Arg0, HKT } from "hkt-core";
263
+
264
+ type Option<T> = Data<{
265
+ Some: [value: T];
266
+ None: [];
267
+ }>;
268
+
269
+ const { Some, None, match } = make<OptionHKT>();
270
+ interface OptionHKT extends HKT {
271
+ return: Option<Arg0<this>>;
272
+ }
273
+
274
+ const map: <T, R>(fn: (value: T) => R) => (opt: Option<T>) => Option<R> = (fn) =>
275
+ match({
276
+ Some: (value) => Some(fn(value)),
277
+ None: () => None,
278
+ });
279
+
280
+ // Using pipe with an ADT
281
+ Some(42).pipe(
282
+ map((n) => n + 1),
283
+ map((n) => n * 2),
284
+ match({
285
+ Some: (n) => console.log("Result:", n),
286
+ None: () => console.log("No value"),
287
+ }),
288
+ );
289
+ //> Result: 86
290
+ ```
291
+
292
+ Under the hood, any value returned by a constructor already has a `.pipe()` method, which takes a sequence of functions and applies them one after another, with each function receiving the result of the previous function.
293
+
294
+ You can also create your own objects with the same `.pipe()` functionality using the exported `Pipeable` interface and `PipeableProto`:
295
+
296
+ ```typescript
297
+ import { type Pipeable, PipeableProto } from "kind-adt";
298
+
299
+ // Create a pipeable object
300
+ const myData = Object.create(PipeableProto);
301
+ myData.value = 42;
302
+
303
+ // Use the pipe method
304
+ const result = myData.pipe(
305
+ (obj) => obj.value * 2,
306
+ (n) => n.toString(),
307
+ ); // => "84"
308
+ ```
309
+
253
310
  ### Provide more readable type signatures
254
311
 
255
312
  Let’s revisit the `Option<T>` example in the quickstart section.
package/index.d.ts CHANGED
@@ -54,6 +54,84 @@ export function make<F extends Tagged | TypeLambda<never, Tagged>>(
54
54
  */
55
55
  export function unwrap<T extends Tagged>(adt: T): ExtractFields<T>;
56
56
 
57
+ /**
58
+ * A type that supports an [RxJS](https://rxjs.dev/api/index/function/pipe)-like
59
+ * (or [Effect](https://github.com/Effect-TS/effect)-like) `.pipe()` method.
60
+ */
61
+ export interface Pipeable {
62
+ /**
63
+ * Pipe the value through a series of functions.
64
+ *
65
+ * **Example**
66
+ *
67
+ * ```typescript
68
+ * import { type Data, make } from "kind-adt";
69
+ *
70
+ * type BoxNumber = Data<{
71
+ * Box: [number];
72
+ * }>;
73
+ * const { Box } = make<BoxNumber>();
74
+ *
75
+ * Box(42).pipe((box) => box._0 + 1, (n) => n * 2, (n) => n.toString()); // => "86"
76
+ * ```
77
+ */
78
+ pipe<A>(this: A): A;
79
+ pipe<A, B = never>(this: A, ab: (a: A) => B): B;
80
+ // prettier-ignore
81
+ pipe<A, B = never, C = never>(this: A, ab: (a: A) => B, bc: (b: B) => C): C;
82
+ // prettier-ignore
83
+ pipe<A, B = never, C = never, D = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D): D;
84
+ // prettier-ignore
85
+ pipe<A, B = never, C = never, D = never, E = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): E;
86
+ // prettier-ignore
87
+ pipe<A, B = never, C = never, D = never, E = never, F = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): F;
88
+ // prettier-ignore
89
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): G;
90
+ // prettier-ignore
91
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H): H;
92
+ // prettier-ignore
93
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I): I;
94
+ // prettier-ignore
95
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J): J;
96
+ // prettier-ignore
97
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K): K;
98
+ // prettier-ignore
99
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L): L;
100
+ // prettier-ignore
101
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M): M;
102
+ // prettier-ignore
103
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N): N;
104
+ // prettier-ignore
105
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O): O;
106
+ // prettier-ignore
107
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P): P;
108
+ // prettier-ignore
109
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q): Q;
110
+ // prettier-ignore
111
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R): R;
112
+ // prettier-ignore
113
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S): S;
114
+ // prettier-ignore
115
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T): T;
116
+ // prettier-ignore
117
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never, U = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T, tu: (t: T) => U): U;
118
+ // prettier-ignore
119
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never, U = never, V = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T, tu: (t: T) => U, uv: (u: U) => V): V;
120
+ // prettier-ignore
121
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never, U = never, V = never, W = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T, tu: (t: T) => U, uv: (u: U) => V, vw: (v: V) => W): W;
122
+ // prettier-ignore
123
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never, U = never, V = never, W = never, X = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T, tu: (t: T) => U, uv: (u: U) => V, vw: (v: V) => W, wx: (w: W) => X): X;
124
+ // prettier-ignore
125
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never, U = never, V = never, W = never, X = never, Y = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T, tu: (t: T) => U, uv: (u: U) => V, vw: (v: V) => W, wx: (w: W) => X, xy: (x: X) => Y): Y;
126
+ // prettier-ignore
127
+ pipe<A, B = never, C = never, D = never, E = never, F = never, G = never, H = never, I = never, J = never, K = never, L = never, M = never, N = never, O = never, P = never, Q = never, R = never, S = never, T = never, U = never, V = never, W = never, X = never, Y = never, Z = never>(this: A, ab: (a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H, hi: (h: H) => I, ij: (i: I) => J, jk: (j: J) => K, kl: (k: K) => L, lm: (l: L) => M, mn: (m: M) => N, no: (n: N) => O, op: (o: O) => P, pq: (p: P) => Q, qr: (q: Q) => R, rs: (r: R) => S, st: (s: S) => T, tu: (t: T) => U, uv: (u: U) => V, vw: (v: V) => W, wx: (w: W) => X, xy: (x: X) => Y, yz: (y: Y) => Z): Z;
128
+ }
129
+
130
+ /**
131
+ * The prototype to build a {@linkcode Pipeable} object.
132
+ */
133
+ export const PipeableProto: Pipeable;
134
+
57
135
  /**************
58
136
  * Main types *
59
137
  **************/
@@ -93,7 +171,8 @@ export type Tagged<
93
171
  ) extends infer Fields ?
94
172
  { readonly [I in IndexOf<Fields> as `_${I}`]: Fields[I] }
95
173
  : never
96
- >;
174
+ > &
175
+ Pipeable;
97
176
 
98
177
  /**
99
178
  * Create an ADT with tagged types.
@@ -303,89 +382,92 @@ export type Constructor<
303
382
  [Type] extends (
304
383
  [Tagged] // Non-generic ADT
305
384
  ) ?
306
- { readonly _tag: Tag } & ((
307
- ...args: ExtractFields<Extract<Type, Tagged<Tag>>>
308
- ) => Type)
385
+ { readonly _tag: Tag } & Pipeable &
386
+ ((...args: ExtractFields<Extract<Type, Tagged<Tag>>>) => Type)
309
387
  : // Generic ADT
310
388
  Type extends TypeLambda<[never], unknown> ?
311
389
  unknown extends _UpperBound<HKTParams<Type>[0]> ?
312
- { readonly _tag: Tag } & (<T = never>(
313
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T]>, Tag>>
314
- ) => ApplyHKT<Type, [T]>)
315
- : { readonly _tag: Tag } & (<
316
- T extends _UpperBound<HKTParams<Type>[0]> = never,
317
- >(
318
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T]>, Tag>>
319
- ) => ApplyHKT<Type, [T]>)
390
+ { readonly _tag: Tag } & Pipeable &
391
+ (<T = never>(
392
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T]>, Tag>>
393
+ ) => ApplyHKT<Type, [T]>)
394
+ : { readonly _tag: Tag } & Pipeable &
395
+ (<T extends _UpperBound<HKTParams<Type>[0]> = never>(
396
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T]>, Tag>>
397
+ ) => ApplyHKT<Type, [T]>)
320
398
  : Type extends TypeLambda<[never, never], unknown> ?
321
399
  [unknown, unknown] extends (
322
400
  [_UpperBound<HKTParams<Type>[0]>, _UpperBound<HKTParams<Type>[1]>]
323
401
  ) ?
324
- { readonly _tag: Tag } & (<T = never, U = never>(
325
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
326
- ) => ApplyHKT<Type, [T, U]>)
402
+ { readonly _tag: Tag } & Pipeable &
403
+ (<T = never, U = never>(
404
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
405
+ ) => ApplyHKT<Type, [T, U]>)
327
406
  : unknown extends _UpperBound<HKTParams<Type>[0]> ?
328
- { readonly _tag: Tag } & (<
329
- T = never,
330
- U extends _UpperBound<HKTParams<Type>[1]> = never,
331
- >(
332
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
333
- ) => ApplyHKT<Type, [T, U]>)
407
+ { readonly _tag: Tag } & Pipeable &
408
+ (<T = never, U extends _UpperBound<HKTParams<Type>[1]> = never>(
409
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
410
+ ) => ApplyHKT<Type, [T, U]>)
334
411
  : unknown extends _UpperBound<HKTParams<Type>[1]> ?
335
- { readonly _tag: Tag } & (<
412
+ { readonly _tag: Tag } & Pipeable &
413
+ (<T extends _UpperBound<HKTParams<Type>[0]> = never, U = never>(
414
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
415
+ ) => ApplyHKT<Type, [T, U]>)
416
+ : { readonly _tag: Tag } & Pipeable &
417
+ (<
418
+ T extends _UpperBound<HKTParams<Type>[0]> = never,
419
+ U extends _UpperBound<HKTParams<Type>[1]> = never,
420
+ >(
421
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
422
+ ) => ApplyHKT<Type, [T, U]>)
423
+ : Type extends TypeLambda<[never, never, never], unknown> ?
424
+ { readonly _tag: Tag } & Pipeable &
425
+ (<
336
426
  T extends _UpperBound<HKTParams<Type>[0]> = never,
337
- U = never,
427
+ U extends _UpperBound<HKTParams<Type>[1]> = never,
428
+ V extends _UpperBound<HKTParams<Type>[2]> = never,
338
429
  >(
339
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
340
- ) => ApplyHKT<Type, [T, U]>)
341
- : { readonly _tag: Tag } & (<
430
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V]>, Tag>>
431
+ ) => ApplyHKT<Type, [T, U, V]>)
432
+ : Type extends TypeLambda<[never, never, never, never], unknown> ?
433
+ { readonly _tag: Tag } & Pipeable &
434
+ (<
342
435
  T extends _UpperBound<HKTParams<Type>[0]> = never,
343
436
  U extends _UpperBound<HKTParams<Type>[1]> = never,
437
+ V extends _UpperBound<HKTParams<Type>[2]> = never,
438
+ W extends _UpperBound<HKTParams<Type>[3]> = never,
344
439
  >(
345
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U]>, Tag>>
346
- ) => ApplyHKT<Type, [T, U]>)
347
- : Type extends TypeLambda<[never, never, never], unknown> ?
348
- { readonly _tag: Tag } & (<
349
- T extends _UpperBound<HKTParams<Type>[0]> = never,
350
- U extends _UpperBound<HKTParams<Type>[1]> = never,
351
- V extends _UpperBound<HKTParams<Type>[2]> = never,
352
- >(
353
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V]>, Tag>>
354
- ) => ApplyHKT<Type, [T, U, V]>)
355
- : Type extends TypeLambda<[never, never, never, never], unknown> ?
356
- { readonly _tag: Tag } & (<
357
- T extends _UpperBound<HKTParams<Type>[0]> = never,
358
- U extends _UpperBound<HKTParams<Type>[1]> = never,
359
- V extends _UpperBound<HKTParams<Type>[2]> = never,
360
- W extends _UpperBound<HKTParams<Type>[3]> = never,
361
- >(
362
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V, W]>, Tag>>
363
- ) => ApplyHKT<Type, [T, U, V, W]>)
440
+ ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V, W]>, Tag>>
441
+ ) => ApplyHKT<Type, [T, U, V, W]>)
364
442
  : Type extends TypeLambda<[never, never, never, never, never], unknown> ?
365
- { readonly _tag: Tag } & (<
366
- T extends _UpperBound<HKTParams<Type>[0]> = never,
367
- U extends _UpperBound<HKTParams<Type>[1]> = never,
368
- V extends _UpperBound<HKTParams<Type>[2]> = never,
369
- W extends _UpperBound<HKTParams<Type>[3]> = never,
370
- X extends _UpperBound<HKTParams<Type>[4]> = never,
371
- >(
372
- ...args: ExtractFields<FilterTagged<ApplyHKT<Type, [T, U, V, W, X]>, Tag>>
373
- ) => ApplyHKT<Type, [T, U, V, W, X]>)
443
+ { readonly _tag: Tag } & Pipeable &
444
+ (<
445
+ T extends _UpperBound<HKTParams<Type>[0]> = never,
446
+ U extends _UpperBound<HKTParams<Type>[1]> = never,
447
+ V extends _UpperBound<HKTParams<Type>[2]> = never,
448
+ W extends _UpperBound<HKTParams<Type>[3]> = never,
449
+ X extends _UpperBound<HKTParams<Type>[4]> = never,
450
+ >(
451
+ ...args: ExtractFields<
452
+ FilterTagged<ApplyHKT<Type, [T, U, V, W, X]>, Tag>
453
+ >
454
+ ) => ApplyHKT<Type, [T, U, V, W, X]>)
374
455
  : Type extends (
375
456
  TypeLambda<[never, never, never, never, never, never], unknown>
376
457
  ) ?
377
- { readonly _tag: Tag } & (<
378
- T extends _UpperBound<HKTParams<Type>[0]> = never,
379
- U extends _UpperBound<HKTParams<Type>[1]> = never,
380
- V extends _UpperBound<HKTParams<Type>[2]> = never,
381
- W extends _UpperBound<HKTParams<Type>[3]> = never,
382
- X extends _UpperBound<HKTParams<Type>[4]> = never,
383
- Y extends _UpperBound<HKTParams<Type>[5]> = never,
384
- >(
385
- ...args: ExtractFields<
386
- FilterTagged<ApplyHKT<Type, [T, U, V, W, X, Y]>, Tag>
387
- >
388
- ) => ApplyHKT<Type, [T, U, V, W, X, Y]>)
458
+ { readonly _tag: Tag } & Pipeable &
459
+ (<
460
+ T extends _UpperBound<HKTParams<Type>[0]> = never,
461
+ U extends _UpperBound<HKTParams<Type>[1]> = never,
462
+ V extends _UpperBound<HKTParams<Type>[2]> = never,
463
+ W extends _UpperBound<HKTParams<Type>[3]> = never,
464
+ X extends _UpperBound<HKTParams<Type>[4]> = never,
465
+ Y extends _UpperBound<HKTParams<Type>[5]> = never,
466
+ >(
467
+ ...args: ExtractFields<
468
+ FilterTagged<ApplyHKT<Type, [T, U, V, W, X, Y]>, Tag>
469
+ >
470
+ ) => ApplyHKT<Type, [T, U, V, W, X, Y]>)
389
471
  : /* support up to 6 type parameters */ never;
390
472
 
391
473
  /**
@@ -1412,7 +1494,7 @@ type HKTParams<F> =
1412
1494
  * type _1 = TolerantResult<OptionHKT>; // => Option<unknown>
1413
1495
  * ```
1414
1496
  */
1415
- export type TolerantResult<F extends TypeLambda> =
1497
+ type TolerantResult<F extends TypeLambda> =
1416
1498
  HKTParams<F> extends infer Params extends unknown[] ?
1417
1499
  ApplyHKT<
1418
1500
  F,
@@ -1453,3 +1535,6 @@ type _CheckVariance<Lower, Upper> =
1453
1535
  : "covariant"
1454
1536
  : [Upper] extends [Lower] ? "contravariant"
1455
1537
  : "invariant";
1538
+
1539
+ /* Ensure TypeScript treats this file as a module to prevent internal from exportation */
1540
+ export {};
package/index.js CHANGED
@@ -28,17 +28,21 @@ export function make(variants) {
28
28
 
29
29
  /* Constructor */
30
30
  const createConstructor = (tag) =>
31
- Object.assign(
32
- renameFunction((...args) => {
33
- const result = { _tag: tag };
34
- for (let i = 0; i < args.length; i++) result["_" + i] = args[i];
35
- return result;
36
- }, tag),
37
- {
38
- _tag: tag,
39
- toJSON: () => ({ _tag: tag }),
40
- [Symbol.for("nodejs.util.inspect.custom")]: () => ({ _tag: tag }),
41
- },
31
+ Object.setPrototypeOf(
32
+ Object.assign(
33
+ renameFunction((...args) => {
34
+ const result = Object.create(PipeableProto);
35
+ result._tag = tag;
36
+ for (let i = 0; i < args.length; i++) result["_" + i] = args[i];
37
+ return result;
38
+ }, tag),
39
+ {
40
+ _tag: tag,
41
+ toJSON: () => ({ _tag: tag }),
42
+ [Symbol.for("nodejs.util.inspect.custom")]: () => ({ _tag: tag }),
43
+ },
44
+ ),
45
+ PipeableFunctionProto,
42
46
  );
43
47
 
44
48
  const result = {
@@ -344,3 +348,42 @@ const stringify = (value) => {
344
348
 
345
349
  return serialize(value, []);
346
350
  };
351
+
352
+ export const PipeableProto = {
353
+ pipe(...fs) {
354
+ // Optimization inspired by Effect
355
+ // https://github.com/Effect-TS/effect/blob/f293e97ab2a26f45586de106b85119c5d98ab4c7/packages/effect/src/Pipeable.ts#L491-L524
356
+ switch (fs.length) {
357
+ case 0:
358
+ return this;
359
+ case 1:
360
+ return fs[0](this);
361
+ case 2:
362
+ return fs[1](fs[0](this));
363
+ case 3:
364
+ return fs[2](fs[1](fs[0](this)));
365
+ case 4:
366
+ return fs[3](fs[2](fs[1](fs[0](this))));
367
+ case 5:
368
+ return fs[4](fs[3](fs[2](fs[1](fs[0](this)))));
369
+ case 6:
370
+ return fs[5](fs[4](fs[3](fs[2](fs[1](fs[0](this))))));
371
+ case 7:
372
+ return fs[6](fs[5](fs[4](fs[3](fs[2](fs[1](fs[0](this)))))));
373
+ case 8:
374
+ return fs[7](fs[6](fs[5](fs[4](fs[3](fs[2](fs[1](fs[0](this))))))));
375
+ case 9:
376
+ return fs[8](
377
+ fs[7](fs[6](fs[5](fs[4](fs[3](fs[2](fs[1](fs[0](this)))))))),
378
+ );
379
+ default: {
380
+ let result = this;
381
+ for (const f of fs) result = f(result);
382
+ return result;
383
+ }
384
+ }
385
+ },
386
+ };
387
+
388
+ const PipeableFunctionProto = { pipe: PipeableProto.pipe };
389
+ Object.setPrototypeOf(PipeableFunctionProto, Function.prototype);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kind-adt",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "🪴 The kind of ADTs you can count on in TypeScript",
5
5
  "keywords": [
6
6
  "typescript",
package/utils.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { ShowOptions } from "showify";
2
-
3
2
  /**
4
3
  * Print arguments including (possibly) ADTs to `stdout` with newline.
5
4
  * @param args The arguments to print.
@@ -25,7 +24,6 @@ import type { ShowOptions } from "showify";
25
24
  * @see {@linkcode show} if you want more control over the output.
26
25
  */
27
26
  export declare function println(...args: unknown[]): void;
28
-
29
27
  /**
30
28
  * Stringify a (possibly) ADT to human-readable format.
31
29
  * @param value The value to stringify.
package/utils.js CHANGED
@@ -29,8 +29,10 @@ const { between, pair, sequence, text, variant } = SerializerNode;
29
29
  * @see {@linkcode show} if you want more control over the output.
30
30
  */
31
31
  export function println(...args) {
32
- getConsole().log(
33
- ...args.map((arg) => (typeof arg === "string" ? arg : show(arg, { colors: true, indent: 2 }))),
32
+ console.log(
33
+ ...args.map((arg) =>
34
+ typeof arg === "string" ? arg : show(arg, { colors: true, indent: 2 }),
35
+ ),
34
36
  );
35
37
  }
36
38
 
@@ -103,7 +105,9 @@ export function show(value, options = {}) {
103
105
  sequence([
104
106
  text(c.cyan(val._tag) + "("),
105
107
  ...flatMap(fields, (field, i, arr) =>
106
- i === arr.length - 1 ? expand(field) : [expand(field), text(", ")],
108
+ i === arr.length - 1 ?
109
+ expand(field)
110
+ : [expand(field), text(", ")],
107
111
  ),
108
112
  ...(body.type === "text" ? [text(")")] : [text(") "), body]),
109
113
  ]),
@@ -150,19 +154,3 @@ const flatMap = (arr, fn) => {
150
154
  }
151
155
  return result;
152
156
  };
153
-
154
- // `console` is not standard in JavaScript. Though rare, it is possible that `console` is not
155
- // available in some environments. We use a proxy to handle this case and ignore errors if `console`
156
- // is not available.
157
- const getConsole = (() => {
158
- let cachedConsole = undefined;
159
- return () => {
160
- if (cachedConsole !== undefined) return cachedConsole;
161
- try {
162
- cachedConsole = new Function("return console")();
163
- } catch {
164
- cachedConsole = null;
165
- }
166
- return cachedConsole;
167
- };
168
- })();