JSPM

pattern-matching-ts

2.0.0
    • ESM via JSPM
    • ES Module Entrypoint
    • Export Map
    • Keywords
    • License
    • Repository URL
    • TypeScript Types
    • README
    • Created
    • Published
    • Downloads 17
    • Score
      100M100P100Q56155F
    • License MIT

    Pattern Matching in typescript

    Package Exports

    • pattern-matching-ts

    This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (pattern-matching-ts) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

    Readme

    Pattern matching in Typescript.

    Pattern Matching is a declarative much more powerful and less verbose alternative to imperatives "if/else" conditions.
    A definition can be found inside Scala Documentation

    “Pattern matching tests whether a given value (or sequence of values) has the shape defined by a pattern, and, if it does, binds the variables in the pattern to the corresponding components of the value (or sequence of values).”

    In Functional Programming languages, there're built-in keywords for Pattern Matching. Typescript though is one language that works very well with Functional Programming but lacks this feature.
    This package aims to bring Pattern Matching feature to Typescript through Discriminated Union Types / Algebraic Data Types.

    npm GitHub license GitHub stars GitHub forks GitHub Workflow Status


    Index



    Installation

    yarn

    yarn add pattern-matching-ts

    npm

    npm install --save pattern-matching-ts

    Usage

    MatchW

    Option MatchW

    import * as M from 'pattern-matching-ts/lib/match'
    import { pipe } from 'fp-ts/lib/function'
    import * as O from 'fp-ts/lib/Option'
    
    const optionMatching = (o: unknown) =>
      pipe(
        o,
        M.matchW('_tag')({
          Some: ({ value }) => 'Something: ' + value,
          None: () => 'Nothing',
          _: () => 'Default'
        })
      )
    
    assert.deepStrictEqual(optionMatching(O.some('data')), 'Something: data')
    assert.deepStrictEqual(optionMatching(O.none), 'Nothing')
    assert.deepStrictEqual(optionMatching((undefined as unknown) as O.None), 'Default')

    Either MatchW

    import * as M from 'pattern-matching-ts/lib/match'
    import { pipe } from 'fp-ts/lib/function'
    import * as E from 'fp-ts/lib/Either'
    
    type RGB = Record<'r' | 'g' | 'b', number>
    const either = (maybeRgb: E.Either<string, RGB>) =>
      pipe(
        maybeRgb,
        M.matchW('_tag')({
          Left: ({ left }) => 'Error: ' + left,
          Right: ({ right: { r, g, b } }) => `Red: ${r} | Green: ${g} | Blue: ${b}`
        })
      )
    
    assert.deepStrictEqual(either(E.right({ r: 255, g: 255, b: 0 })), 'Red: 255 | Green: 255 | Blue: 0')

    Default MatchW

    import * as M from 'pattern-matching-ts/lib/match'
    import { pipe } from 'fp-ts/lib/function'
    
    interface ServerResponse<Code extends string | number> {
      readonly code: Code
    }
    
    interface Response<Body> {
      readonly response: {
        readonly body: Body
      }
    }
    
    interface Success extends ServerResponse<200>, Response<ReadonlyArray<string>> {}
    
    interface NotFoundError extends ServerResponse<404> {}
    
    interface ServerError extends ServerResponse<500> {
      readonly detail: string
    }
    
    type Responses = Success | NotFoundError | ServerError
    
    const matchResponse = (response: Responses) =>
      pipe(
        response,
        M.matchW('code')({
          500: ({ detail }) => ({ message: 'Internal server error', detail }),
          404: () => ({ message: 'The page cannot be found!' }),
          200: ({ response }) => response.body,
          _: () => 'Unexpected response'
        })
      )
    
    assert.deepStrictEqual(either(E.right({ r: 255, g: 255, b: 0 })), 'Red: 255 | Green: 255 | Blue: 0')
    assert.deepStrictEqual(matchResponse({ code: 200, response: { body: ['data'] } }), ['data'])
    assert.deepStrictEqual(matchResponse({ code: 500, detail: 'Cannot connect to the database' }), {
      message: 'Internal server error',
      detail: 'Cannot connect to the database'
    })
    assert.deepStrictEqual(matchResponse({ code: 404 }), { message: 'The page cannot be found!' })

    Match

    Option Match

    import * as M from 'pattern-matching-ts/lib/match'
    import * as O from 'fp-ts/lib/Option'
    
    const optionMatching = M.match<O.Option<string>, string>({
      Some: (x) => `Something: ${x.value}`,
      None: () => 'Nothing'
    })
    
    assert.deepStrictEqual(optionMatching(O.some('data')), 'Something: data')
    assert.deepStrictEqual(optionMatching(O.none), 'Nothing')

    Default Match

    import * as M from 'pattern-matching-ts/lib/match'
    
    interface ChangeColor<T = number> {
      readonly _tag: 'ChangeColor'
      readonly value: {
        readonly r: T
        readonly g: T
        readonly b: T
      }
    }
    interface Move<T = number> {
      readonly _tag: 'Move'
      readonly value: {
        readonly x: T
        readonly y: T
      }
    }
    interface Write {
      readonly _tag: 'Write'
      readonly value: {
        readonly text: string
      }
    }
    
    type Cases = ChangeColor<number> | Move | Write
    const matchMessage = M.match<Cases, string>({
      ChangeColor: ({ value: { r, g, b } }) => `Change the color to Red: ${r} | Green: ${g} | Blue: ${b}`,
      Move: ({ value: { x, y } }) => `Move in the x direction: ${x} and in the y direction: ${y}`,
      Write: ({ value: { text } }) => `Text message: ${text}`,
      _: () => 'Default message'
    })
    
    const ChangeColor = ({ r, g, b }: ChangeColor<number>['value']): ChangeColor<number> => ({
      _tag: 'ChangeColor',
      value: { r, g, b }
    })
    
    const Move = ({ x, y }: Move['value']): Move => ({
      _tag: 'Move',
      value: { x, y }
    })
    
    const Write = ({ text }: Write['value']): Write => ({
      _tag: 'Write',
      value: { text }
    })
    
    assert.deepStrictEqual(
      matchMessage(Move({ x: 500, y: 100 })),
      'Move in the x direction: 500 and in the y direction: 100'
    )
    
    assert.deepStrictEqual(
      matchMessage(ChangeColor({ r: 12, g: 20, b: 30 })),
      'Change the color to Red: 12 | Green: 20 | Blue: 30'
    )
    
    assert.deepStrictEqual(matchMessage(Write({ text: 'my message' })), 'Text message: my message')

    Here's a blog post that introduces the API. 👉 Pattern Matching in Typescript

    MIT