typescript-monads
Version:
Write cleaner TypeScript
161 lines • 5.41 kB
JavaScript
import { Reader } from './reader';
/**
* Creates a Reader monad with the given function.
*
* @typeParam TConfig - The environment/configuration type
* @typeParam TOut - The result type
* @param fn - Function that takes a configuration and returns a value
* @returns A Reader containing the provided function
*
* @example
* // Create a Reader that greets a user
* const greet = reader<{name: string}, string>(config => `Hello, ${config.name}!`);
*
* // Run it with a configuration
* const greeting = greet.run({name: 'Alice'}); // Returns 'Hello, Alice!'
*/
export function reader(fn) {
return new Reader(fn);
}
/**
* Creates a Reader that always returns a constant value, ignoring the environment.
*
* @typeParam TConfig - The environment/configuration type
* @typeParam TOut - The result type
* @param value - The constant value to return
* @returns A Reader that always produces the given value
*
* @example
* // Create a Reader that always returns 42
* const constReader = readerOf<any, number>(42);
* constReader.run(anyEnvironment) // Returns 42
*/
export function readerOf(value) {
return Reader.of(value);
}
/**
* Creates a Reader that returns the environment itself.
*
* @typeParam TConfig - The environment/configuration type
* @returns A Reader that returns its environment
*
* @example
* // Create a Reader that provides access to its environment
* const askReader = ask<Config>();
*
* // Use it to extract a specific part of the environment
* const getApiUrl = askReader.map(config => config.apiUrl);
*/
export function ask() {
return Reader.ask();
}
/**
* Creates a Reader that accesses a specific part of the environment.
*
* @typeParam TConfig - The environment type
* @typeParam TOut - The type of the property to access
* @param accessor - Function that extracts a value from the environment
* @returns A Reader that returns the specified part of the environment
*
* @example
* // Create a Reader that accesses the apiUrl from a config object
* const getApiUrl = asks<AppConfig, string>(config => config.apiUrl);
*
* // Run it with a configuration
* const url = getApiUrl.run({ apiUrl: 'https://api.example.com', timeout: 5000 });
* // url is 'https://api.example.com'
*/
export function asks(accessor) {
return Reader.asks(accessor);
}
/**
* Combines multiple Readers into a single Reader that returns an array of results.
*
* @typeParam TConfig - The shared environment type
* @typeParam TOut - The type of each Reader's output
* @param readers - Array of Readers to combine
* @returns A Reader that produces an array of all results
*
* @example
* // Define individual Readers
* const getName = asks<UserConfig, string>(c => c.name);
* const getAge = asks<UserConfig, number>(c => c.age);
* const getEmail = asks<UserConfig, string>(c => c.email);
*
* // Combine them to get all user info at once
* const getUserInfo = sequence([getName, getAge, getEmail]);
*
* // Run with a configuration
* const userInfo = getUserInfo.run({
* name: 'Alice',
* age: 30,
* email: 'alice@example.com'
* });
* // userInfo is ['Alice', 30, 'alice@example.com']
*/
export function sequence(readers) {
return Reader.sequence(readers);
}
/**
* Combines multiple Readers into a single Reader, aggregating their results with a reducer function.
*
* @typeParam TConfig - The shared environment type
* @typeParam TOut - The type of each Reader's output
* @typeParam TAcc - The type of the accumulated result
* @param readers - Array of Readers to combine
* @param reducer - Function that combines the results
* @param initialValue - Initial value for the accumulator
* @returns A Reader that produces the aggregated result
*
* @example
* // Define Readers for different stats
* const getActiveUsers = asks<Dependencies, number>(
* deps => deps.userService.countActiveUsers()
* );
* const getPendingOrders = asks<Dependencies, number>(
* deps => deps.orderService.countPendingOrders()
* );
*
* // Combine into a dashboard stats object
* const getDashboardStats = traverse(
* [getActiveUsers, getPendingOrders],
* (acc, count, index) => {
* if (index === 0) acc.activeUsers = count;
* else if (index === 1) acc.pendingOrders = count;
* return acc;
* },
* { activeUsers: 0, pendingOrders: 0 }
* );
*/
export function traverse(readers, reducer, initialValue) {
return Reader.traverse(readers, reducer, initialValue);
}
/**
* Combines the results of multiple Readers with a mapping function.
*
* @typeParam TConfig - The shared environment type
* @typeParam Args - Tuple type of Reader results
* @typeParam R - The type of the combined result
* @param readers - Tuple of Readers
* @param fn - Function to combine the results
* @returns A Reader that produces the combined result
*
* @example
* // Define individual Readers
* const getUser = asks<AppDeps, User>(deps => deps.userService.getCurrentUser());
* const getPermissions = asks<AppDeps, string[]>(deps => deps.authService.getPermissions());
*
* // Combine them into a user profile object
* const getUserProfile = combine(
* [getUser, getPermissions],
* (user, permissions) => ({
* id: user.id,
* name: user.name,
* permissions
* })
* );
*/
export function combine(readers, fn) {
return Reader.combine(readers, fn);
}
//# sourceMappingURL=reader.factory.js.map