IO represents synchronous side-effectful computations that never fail. IO actions are lazy and only executed when the run() method is called, enabling controlled side effect management.
Create IO instances from values and functions.
/**
* Create IO from pure value
* @param a - Value to wrap in IO
* @returns IO that returns the value when run
*/
function of<A>(a: A): IO<A>;
/**
* Create IO from lazy computation
* @param f - Function to execute
* @returns IO that executes function when run
*/
function io<A>(f: Lazy<A>): IO<A>;
/**
* Never-resolving IO (infinite computation)
*/
const never: IO<never>;Usage Examples:
import { IO, of as ioOf } from "fp-ts/lib/IO";
// Pure value
const constantIO = ioOf(42);
const result1 = constantIO.run(); // 42
// Lazy computation
const randomIO = new IO(() => Math.random());
const result2 = randomIO.run(); // random number
const result3 = randomIO.run(); // different random number
// Side-effectful computation
const logIO = (message: string) => new IO(() => {
console.log(message);
return undefined;
});
logIO("Hello World").run(); // prints and returns undefinedTransform IO computations while preserving the IO context.
/**
* Map function over IO result
* @param f - Transformation function
* @returns Function that maps over IO
*/
function map<A, B>(f: (a: A) => B): (fa: IO<A>) => IO<B>;
/**
* Apply function in IO to value in IO
* @param fab - IO containing function
* @returns Function that applies function to IO value
*/
function ap<A, B>(fab: IO<(a: A) => B>): (fa: IO<A>) => IO<B>;
/**
* Sequence two IOs, keeping first result
* @param fb - Second IO to execute
* @returns Function that sequences IOs
*/
function applyFirst<A, B>(fb: IO<B>): (fa: IO<A>) => IO<A>;
/**
* Sequence two IOs, keeping second result
* @param fb - Second IO to execute
* @returns Function that sequences IOs
*/
function applySecond<A, B>(fb: IO<B>): (fa: IO<A>) => IO<B>;Usage Examples:
import { IO, map, ap } from "fp-ts/lib/IO";
// Transform result
const numberIO = new IO(() => 21);
const doubledIO = map((n: number) => n * 2)(numberIO);
const result = doubledIO.run(); // 42
// Apply function
const addIO = new IO(() => (x: number) => (y: number) => x + y);
const xIO = new IO(() => 10);
const yIO = new IO(() => 20);
const sumIO = ap(ap(addIO)(xIO))(yIO);
const sum = sumIO.run(); // 30Chain IO computations in sequence.
/**
* Chain IO computations
* @param f - Function returning IO
* @returns Function that chains IOs
*/
function chain<A, B>(f: (a: A) => IO<B>): (fa: IO<A>) => IO<B>;
/**
* Flatten nested IO
* @param mma - IO containing IO
* @returns Flattened IO
*/
function flatten<A>(mma: IO<IO<A>>): IO<A>;Usage Examples:
import { IO, chain } from "fp-ts/lib/IO";
// Chain operations
const getNumber = new IO(() => 5);
const processNumber = (n: number) => new IO(() => {
console.log(`Processing ${n}`);
return n * n;
});
const chainedIO = chain(processNumber)(getNumber);
const result = chainedIO.run(); // prints "Processing 5", returns 25IO implements various type class instances for generic operations.
/**
* Main IO type class instances
*/
const io: Monad1<URI> & MonadIO1<URI>;
/**
* Semigroup instance for IO
* @param S - Semigroup for contained type
* @returns Semigroup that combines IO results
*/
function getSemigroup<A>(S: Semigroup<A>): Semigroup<IO<A>>;
/**
* Monoid instance for IO
* @param M - Monoid for contained type
* @returns Monoid that combines IO results
*/
function getMonoid<A>(M: Monoid<A>): Monoid<IO<A>>;Convert between IO and other effect types.
/**
* Convert IO to Task
* @param ma - IO to convert
* @returns Task that executes IO synchronously
*/
function fromIO<A>(ma: IO<A>): Task<A>;
/**
* Lift IO into other monads
* @param M - MonadIO instance
* @returns Function that lifts IO
*/
function liftIO<M extends URIS>(M: MonadIO1<M>): <A>(ma: IO<A>) => Kind<M, A>;Helpful utilities for working with IO.
/**
* Execute multiple IOs in sequence, ignoring results
* @param ios - Array of IOs to execute
* @returns IO that executes all in sequence
*/
function sequence_<A>(ios: Array<IO<A>>): IO<void>;
/**
* Execute IO and return result along with execution time
* @param ma - IO to time
* @returns IO returning tuple of [result, milliseconds]
*/
function time<A>(ma: IO<A>): IO<[A, number]>;Usage Examples:
import { IO, sequence_ } from "fp-ts/lib/IO";
// Execute multiple side effects
const log1 = new IO(() => console.log("First"));
const log2 = new IO(() => console.log("Second"));
const log3 = new IO(() => console.log("Third"));
const allLogs = sequence_([log1, log2, log3]);
allLogs.run(); // prints all three messages in orderWhile IO never fails, you can handle errors from underlying computations.
/**
* Try to execute IO, catching exceptions
* @param f - Function that may throw
* @returns IO returning Either with result or error
*/
function tryCatch<A>(f: Lazy<A>): IO<Either<Error, A>>;
/**
* Try to execute IO with custom error handler
* @param f - Function that may throw
* @param onError - Function to handle errors
* @returns IO returning Either with result or custom error
*/
function tryCatchK<E, A>(f: Lazy<A>, onError: (e: unknown) => E): IO<Either<E, A>>;Usage Examples:
import { IO, tryCatch } from "fp-ts/lib/IO";
import { fold } from "fp-ts/lib/Either";
// Safe JSON parsing
const parseJSON = (str: string) => tryCatch(() => JSON.parse(str));
const safeParseIO = parseJSON('{"name": "Alice"}');
const result = safeParseIO.run();
const message = fold(
(error: Error) => `Parse failed: ${error.message}`,
(value: unknown) => `Parsed: ${JSON.stringify(value)}`
)(result);
console.log(message); // "Parsed: {"name":"Alice"}"// Core IO type
class IO<A> {
readonly _A!: A;
readonly _URI!: URI;
constructor(readonly run: Lazy<A>) {}
// Instance methods (deprecated in favor of pipeable operations)
map<B>(f: (a: A) => B): IO<B>;
ap<B>(fab: IO<(a: A) => B>): IO<B>;
chain<B>(f: (a: A) => IO<B>): IO<B>;
// Utility methods
inspect(): string;
toString(): string;
}
// URI for type-level programming
const URI = 'IO';
type URI = typeof URI;
// Lazy computation type
type Lazy<A> = () => A;