fearless-io
    TypeScript icon, indicating that this package has built-in type declarations

    16.2.1 • Public • Published

    Build Status npm

    A type-safe, functional, performant, lawful, composable data structure that solves practical problems of effect-full code in node and browser.

    Index

    Installation

    npm i fearless-io

    Usage

    import {IO, defaultRuntime} from 'fearless-io'
     
    // Create a pure version of `console.log` called `putStrLn`
    const putStrLn = IO.encase((str: string) => console.log(str))
     
    const hello = putStrLn('Hello World!')
     
    const runtime = defaultRuntime()
    runtime.unsafeExecute(hello)

    Getting Started

    Type Signature

    interface FIO<R, E, A> {
      // ... Operators
    }

    FIO takes in three type params viz. —

    1. R Represents the type of environment needed to execute this IO (more).
    2. E The error types that can be emitted while this IO is executing.
    3. A The type of the success value that will be emitted by the IO on completion.

    Using these three type params you can fairly represent any side-effect. For example lets say there is function Greet which simply prints "Hello World" —

      const Greet = () => console.log('Hello World!')

    To represent Greet

    1. R could be unknown: since console.log works everywhere.
    2. E could be never: Printing anything on console never fails.
    3. A could be void: The output of running the program is basically nothing.
    const GreetIO: FIO<unknown, never, void>

    Creating a FIO

    There are multiple ways through which you can create an instance of FIO viz. FIO.from or FIO.encase etc. Refer to the API documentation to learn about all the ways.

    Once of the easiest ways to create a FIO is through FIO.encase.

    + import {FIO} from 'fearless-io'
     
      const Greet = () => console.log('Hello World!')
    + const GreetIO = FIO.encase(Greet)

    Calling GreetIO() returns a pure data structure which represents a side-effect, that —

    1. Can execute in any environment without any special needs.
    2. Never fails.
    3. Resolves with a void.

    Executing FIO

    Execution of FIO happens through a Runtime.

    - import {FIO} from 'fearless-io'
    + import {FIO, defaultRuntime} from 'fearless-io'
     
      const Greet = () => console.log('Hello World!')
      const GreetIO = FIO.encase(Greet)
    + defaultRuntime().unsafeExecute(GreetIO())

    Serial Execution

    Since these data structures don't specify how or when they are going to be executed, writing them one after the other in procedural style will not guarantee any order of execution, for Eg —

    +  import {FIO} from 'fearless-io'
    +  const putStrLn = FIO.encase((msg: string) => console.log(msg))
    + 
    +  const foo = putStrLn('foo')
    +  const bar = putStrLn('bar')

    In the above code either foo or bar can be printed first depending on internal prioritization and scheduling algorithms that FIO uses. To ensure that foo is printed first and bar is printed second one must use the and operator.

      import {FIO} from 'fearless-io'
      const putStrLn = FIO.encase((msg: string) => console.log(msg))
     
      const fooIO = putStrLn('foo')
      const barIO = putStrLn('bar')
     
    + const fooBar = fooIO.and(barIO)

    fooBar is a new FIO object of type FIO<unknown, never, void>.

    - import {FIO} from 'fearless-io'
    + import {FIO, defaultRuntime} from 'fearless-io'
      const putStrLn = FIO.encase((msg: string) => console.log(msg))
     
      const fooIO = putStrLn('foo')
      const barIO = putStrLn('bar')
     
      const fooBar = fooIO.and(barIO)
    + defaultRuntime().unsafeExecute(fooBar)

    Parallel Execution

    Similar to the and operator, the par operator runs the two IOs in parallel. For eg.

    Create the two IOs

    +  import {FIO} from 'fearless-io'
    + 
    +  const foo = FIO.timeout('foo', 1000)
    +  const bar = FIO.timeout('bar', 1500)

    Combine them using par

    - import {FIO} from 'fearless-io'
     
      const foo = FIO.timeout('foo', 1000)
      const bar = FIO.timeout('bar', 1500)
    + const fooBar = foo.par(bar)

    Execute the created IO

    - import {FIO} from 'fearless-io'
    + import {FIO, defaultRuntime} from 'fearless-io'
     
      const foo = FIO.timeout('foo', 1000)
      const bar = FIO.timeout('bar', 1500)
      const fooBar = foo.zip(bar)
     
    + defaultRuntime().unsafeExecute(fooBar)

    The program fooBar will complete in 1500ms because both are executed in parallel.

    Other more powerful operators can be found at API Documentation.

    Cancellation

    Executing an IO returns a cancel callback. Essentially a function that when called, aborts the IO from any further execution and synchronously releases all the acquired resources.

    Create an IO

    + import {FIO} from 'fearless-io'
    + const delayIO = FIO.timeout('Hello World', 1000)

    Execute by passing it to defaultRuntime

    - import {FIO} from 'fearless-io'
    + import {FIO, defaultRuntime} from 'fearless-io'
      const delayIO = FIO.timeout('Hello World', 1000)
    + const cancel = defaultRuntime().unsafeExecute(delayIO)

    Calling the cancelling callback.

      import {FIO, defaultRuntime} from 'fearless-io'
      const delayIO = FIO.timeout('Hello World', 1000)
      const cancel = defaultRuntime().execute(delayIO)
    + cancel()

    As soon as cancel is called internally the timeout is cancelled.

    Custom Environment

    By default any FIO instance would not need any env. This can be customized based on what the program needs to perform. For example, if a program needs to read a config and print out the port set in it one could do something like this —

    Config

    Say we already have a Config interface, with only one property —

    + interface Config {
    +   port: number
    + }

    ConfigEnv

    Next we create an Environment that returns a config

      interface Config {
        port: number
      }
    + interface ConfigEnv {
    +   config: Config
    + }

    Helper functions

    We add getPort which picks the port and putStrLn which is a wrapper over console.log to make it pure.

    + import {FIO} from 'fearless-io'
      interface Config {
        port: number
      }
      interface ConfigEnv {
        config: Config
      }
    + const getPort = FIO.access((config: Config) => config.port)
    + const putStrLn = FIO.encase((message: string) => console.log(message))

    Create program

    Using the chain operator one can now chain them one after the other —

      import {FIO} from 'fearless-io'
      interface Config {
        port: number
      }
      interface ConfigEnv {
        config: Config
      }
      const getPort = FIO.access((config: Config) => config.port)
      const putStrLn = FIO.encase((message: string) => console.log(message))
     
    + const program = getPort().chain(putStrLn)

    Provide Env

    You can provide the env directly to a FIO instance without executing it using the provide method.

      import {FIO} from 'fearless-io'
    + import config from 'node-config'
      interface Config {
        port: number
      }
      interface ConfigEnv {
        config: Config
      }
      const getPort = FIO.access((config: Config) => config.port)
      const putStrLn = FIO.encase((message: string) => console.log(message))
     
      const program = getPort().chain(putStrLn)
     
    + const env = {
    +   config: config
    + }
    + const program0 = program.provide(env)

    Running the program

    Running the program can be done by using the runtime.

    - import {FIO} from 'fearless-io'
    + import {FIO, defaultRuntime} from 'fearless-io'
      import config from 'node-config'
      interface Config {
        port: number
      }
      interface ConfigEnv {
        config: Config
      }
      const getPort = FIO.access((config: Config) => config.port)
      const putStrLn = FIO.encase((message: string) => console.log(message))
     
      const program = getPort().chain(putStrLn)
     
      const env = {
        config: config
      }
      const program0 = program.provide(env)
    + defaultRuntime().unsafeExecute(program0)

    Next Steps

    Checkout a fully functional example here.

    Credits

    FIO is heavily inspired by the following libraries —

    Install

    npm i fearless-io

    DownloadsWeekly Downloads

    71

    Version

    16.2.1

    License

    ISC

    Unpacked Size

    5.53 MB

    Total Files

    226

    Last publish

    Collaborators

    • tusharmathur