Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/takayuki-y5991/pipeline-ts
A minimal library that provides a functional pipeline mechanism in typescript
https://github.com/takayuki-y5991/pipeline-ts
functional-programming typescript
Last synced: 4 days ago
JSON representation
A minimal library that provides a functional pipeline mechanism in typescript
- Host: GitHub
- URL: https://github.com/takayuki-y5991/pipeline-ts
- Owner: Takayuki-Y5991
- Created: 2024-07-17T14:07:50.000Z (4 months ago)
- Default Branch: master
- Last Pushed: 2024-07-23T13:04:13.000Z (4 months ago)
- Last Synced: 2024-10-28T15:27:43.232Z (20 days ago)
- Topics: functional-programming, typescript
- Language: TypeScript
- Homepage:
- Size: 65.4 KB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# PipeLineTS
PipeLineTS is a minimal dependency-free library for composing pipelines in TypeScript. It allows you to compose both synchronous and asynchronous functions, ensuring type safety throughout the pipeline.
## Features
- Type-safe function composition
- Supports both synchronous and asynchronous functions
- Handles success and failure cases with a unified `Result` type## Installation
You can install this package using pnpm:
```sh
pnpm add ts-dependency-free-pipeline
```## Usage
Define Result Types and Utility FunctionsCreate a file named `result.ts` with the following content:
```typescript
export class Success {
readonly isSuccess = true;
readonly isFailure = false;constructor(public readonly value: T) {}
}export class Failure {
readonly isSuccess = false;
readonly isFailure = true;constructor(public readonly error: E) {}
}export type Result = Success | Failure;
export type AsyncResult = Result | Promise>;export const isSuccess = (result: Result): result is Success =>
result.isSuccess;
export const isFailure = (result: Result): result is Failure =>
result.isFailure;export const success = (value: T): Result => new Success(value);
export const failure = (error: E): Result => new Failure(error);export const of = (value: T): Result => success(value);
export const match =
({
onSuccess,
onFailure,
}: {
onSuccess: (value: T) => RS | Promise;
onFailure: (error: E) => RF | Promise;
}) =>
async (result: Result): Promise =>
isSuccess(result) ? onSuccess(result.value) : onFailure(result.error);export const fromPromise = async (
promise: Promise
): Promise> => {
try {
const value = await promise;
return success(value);
} catch (error) {
return failure(error as E);
}
};
```## Define pipe Function
Create a file named pipeline.ts with the following content:
```typescript
import { AsyncResult, isFailure, Result, Success } from "./result";
type Last = T extends [...infer _, infer L] ? L : never;
type PipeFn = (arg: In) => AsyncResult;
type LastReturnType = K extends keyof T
? T[K] extends PipeFn
? S
: never
: never;
type ExtractError = T[number] extends PipeFn
? E
: never;type Pipeline = {
[K in keyof T]: K extends "0"
? T[K] extends PipeFn
? PipeFn
: never
: T[K] extends PipeFn
? PipeFn, S, E>
: never;
};/**
* The `pipe` function composes multiple functions, handling both synchronous and asynchronous processes.
* @template T - The tuple of functions.
* @template ExtractError - The error type extracted from the tuple of functions.
* @param {...Pipeline>} fns - The functions to compose.
* @returns {Function} A function that takes the input of the first function and returns a `Promise` resolving to a `Result` of the last function's output type and the error type.
*
* @example
* const pipeline = pipe(
* async (input: string) => success(parseInt(input)),
* async (num: number) => success(num + 1),
* async (num: number) => success(num.toString())
* );
*
* pipeline("42").then(result =>
* match({
* onSuccess: val => console.log("Success:", val),
* onFailure: err => console.log("Error:", err)
* })(result)
* );
*/
export const pipe = <
T extends [PipeFn, ...PipeFn[]]
>(
...fns: Pipeline>
): ((
arg: Parameters[0]
) => Promise<
Result, ExtractError>
>) => {
return async (
arg: Parameters[0]
): Promise<
Result, ExtractError>
> => {
let result: Result> = await fns[0](arg);
for (const fn of fns.slice(1)) {
if (isFailure(result)) break;
result = await fn((result as Success).value);
}
return result;
};
};
```
## Example Usage```typescript
import { pipe } from './pipeline';
import { success, failure, match, Result } from './result';// Define your functions
const parseNumber = async (input: string): Promise> =>
isNaN(Number(input)) ? failure("Not a number") : success(Number(input));const increment = async (num: number): Promise> =>
success(num + 1);const stringify = async (num: number): Promise> =>
success(num.toString());// Create a pipeline
const pipeline = pipe(parseNumber, increment, stringify);// Execute the pipeline
pipeline("42").then(result =>
match({
onSuccess: val => console.log("Success:", val),
onFailure: err => console.log("Error:", err)
})(result)
);
```## License
This project is licensed under the MIT License