Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

newtype-ts

gcanti1.6mMIT0.3.5TypeScript support: included

Implementation of newtypes in TypeScript

typescript, newtype, functional-programming

readme

build status npm downloads

Installation

To install the stable version:

npm i newtype-ts

Note. newtype-ts depends on fp-ts and monocle-ts, starting from 0.3.0 you must install both fp-ts and monocle-ts manually (fp-ts and monocle-ts are listed in peerDependency)

Motivation

A common programming practice is to define a type whose representation is identical to an existing one but which has a separate identity in the type system.

type USD = number
type EUR = number

const myamount: USD = 1

declare function change(usd: USD): EUR
declare function saveAmount(eur: EUR): void

saveAmount(change(myamount)) // ok
saveAmount(myamount) // opss... this is also ok because both EUR and USD are type alias of number!

Usage

Newtypes

Let's define a newtype for the EUR currency

import { Newtype, iso } from 'newtype-ts'

interface EUR extends Newtype<{ readonly EUR: unique symbol }, number> {}

// isoEUR: Iso<EUR, number>
const isoEUR = iso<EUR>()

// myamount: EUR
const myamount = isoEUR.wrap(0.85)

// n: number = 0.85
const n = isoEUR.unwrap(myamount)

declare function saveAmount(eur: EUR): void

saveAmount(0.85) // static error: Argument of type '0.85' is not assignable to parameter of type 'EUR'
saveAmount(myamount) // ok

By definition a "newtype" must have the exact same runtime representation as the value that it stores, e.g. a value of type EUR is just a number at runtime.

For the Iso type, see the monocle-ts documentation.

Refinements

An Integer is a refinement of number

import { Newtype, prism } from 'newtype-ts'

interface Integer extends Newtype<{ readonly Integer: unique symbol }, number> {}

const isInteger = (n: number) => Number.isInteger(n)

// prismInteger: Prism<number, Integer>
const prismInteger = prism<Integer>(isInteger)

// oi: Option<Integer>
const oi = prismInteger.getOption(2)

declare function f(i: Integer): void

f(2) // static error: Argument of type '2' is not assignable to parameter of type 'Integer'
oi.map(f) // ok

For the Prism type, see the monocle-ts documentation.

Builtin refinements

  • Char
  • Integer
  • Negative
  • NegativeInteger
  • NonNegative
  • NonNegativeInteger
  • NonPositive
  • NonPositiveInteger
  • NonEmptyString
  • NonZero
  • NonZeroInteger
  • Positive
  • PositiveInteger
import { NonZero, prismNonZero } from 'newtype-ts/lib/NonZero'

// a total function
const safeDivide = (numerator: number, denominator: NonZero): number => {
  return numerator / prismNonZero.reverseGet(denominator)
}

// result: Option<number>
const result = prismNonZero.getOption(2).map(denominator => safeDivide(2, denominator))

TypeScript compatibility

The stable version is tested against TypeScript 3.5.1

newtype-ts version required typescript version required fp-ts version required monocle-ts version
0.3 3.5.1+ 2.0.0-rc.6+ 2.0.0-rc.1+
<= 0.2.4 2.8+ 1.0.0+ 1.0.0+

Performance

const double = n => n * 2
const doubleEUR = eurIso.modify(double)

Test double(2) vs doubleEUR(eurIso.wrap(2))

Results (node v8.9.3)

double x 538,301,203 ops/sec ±0.45% (87 runs sampled)
doubleEUR x 536,575,600 ops/sec ±0.27% (87 runs sampled)

Recipes

How to lift a function

const double = (n: number): number => n * 2

// doubleEUR: (s: EUR) => EUR
const doubleEUR = eurIso.modify(double)

Documentation

changelog

Changelog

Tags:

  • [New Feature]
  • [Bug Fix]
  • [Breaking Change]
  • [Documentation]
  • [Internal]
  • [Polish]
  • [Experimental]
  • [Deprecation]

Note: Gaps between patch versions are faulty/broken releases. Note: A feature tagged as Experimental is in a high state of flux, you're at risk of it changing without notice.

0.3.5

  • Polish
    • Add missing pure annotations, #31 (@OliverJAsh)

0.3.4

  • Bug Fix
    • don't set target: es6 in tsconfig.build-es6.json (@gcanti)
  • Internal
    • upgrade to latest docs-ts (@gcanti)

0.3.3

  • Bug Fix
    • rewrite es6 imports (@gcanti)

0.3.2

0.3.1

Fix es6 modules build (@gcanti)

0.3.0

  • Breaking Change
    • upgrade to `fp-ts@2.xandmonocle-ts@2.x` (@gcanti)
    • remove deprecated APIs (@gcanti)
      • Carrier type
    • remove over function (@gcanti)
    • remove unsafeCoerce function (@gcanti)

0.2.4

  • Polish
    • better integer detection in Integer prism (@tatchi)

0.2.3

  • Polish
    • make Newtype readonly (@gcanti)

0.2.2

  • New Feature
    • add Char, closes #12 (@gcanti)
    • add NonEmptyString, closes #13 (@gcanti)

0.2.1

  • New Feature
    • add URIOf type (@gcanti)
    • add prism management (@gcanti)
      • Concat type
      • Extends type
      • prism function
    • add basic newtypes for number (@gcanti)
      • Integer
      • Negative
      • NegativeInteger
      • NonNegative
      • NonNegativeInteger
      • NonPositive
      • NonPositiveInteger
      • NonZero
      • NonZeroInteger
      • Positive
      • PositiveInteger
  • Deprecation
    • deprecate Carrier in favour of CarrierOf (@gcanti)

0.2.0

0.1.2

  • New Feature
    • export unsafeCoerce (@gcanti)

0.1.1

  • Internal
    • optimize iso creation (@gcanti)
    • upgrade to latest prettier, 1.9.2 (@gcanti)
    • upgrade to latest TypeScript, 2.6.2 (@gcanti)

0.1.0

  • Breaking Change
    • upgrade to fp-ts 0.6 (@gcanti)

0.0.1

Initial release