0.3.5 • Published 2 years ago

newtype-ts v0.3.5

Weekly downloads
27,297
License
MIT
Repository
github
Last release
2 years ago

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 versionrequired typescript versionrequired fp-ts versionrequired monocle-ts version
0.33.5.1+2.0.0-rc.6+2.0.0-rc.1+
<= 0.2.42.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

@squiz/dxp-cli@squiz/dxpcloset-viewer@closet-viewer/closet-viewer@everything-registry/sub-chunk-2266@viamedici-spc/configurator@arthurgubaidullin/nx-embed-dependencies@bitgo/identity-token@bitgo/public-types@body-link/schemas@docmaps/sdk@epicallan/money-ts@guardian/grid-client@hsiwe/schema-types-generator@futureverse/sylo-notifications-sdk@futureverse/sylo-protocol-sdk@isomorphic-typescript/ts-monorepo@jmorecroft67/repositorythreat-model-managerts-endpoint-avengerts-aerodata-francets-sharedstart-slicemachinetreeqlite-http-servertestcafe-reporter-dashboardtestcafe-reporter-dashboard-devextremetestcafe-reporter-dashboard-testyl-ddd-tsverdadvelitlaborumuse-font-metrics@pagopa/cloudgaap-commons-ts@agiledigital/jiralint-lib@0x706b/morphic@imtbl/imx-link-types@imtbl/imx-sdk@io-sign/io-sign@matechs/aio@marlowe.io/adapter@marlowe.io/language-core-v1@marlowe.io/runtime-core@marlowe.io/runtime-lifecycle@marlowe.io/runtime-rest-client@marlowe.io/wallet@marlowe.nicolas/language-core-v1@marlowe.nicolas/legacy-adapter@marlowe.nicolas/legacy-runtime@marlowe.tmp/language-core-v1@marlowe.tmp/legacy-adapter@marlowe.tmp/legacy-runtime@rockset/core@rockset/dev-server@resolve-js/eventstore-base@ryb73/datalocker-api-types@qdev/utils-ts@novastar/native@nvoy/base@nvoy/react-sdk@prismicio/editor-fields@prismicio/types-internal@projectdiscovery/interactsh@projectdiscovery/interactsh-cli@projectdiscovery/interactsh-client@projectdiscoveryio/interactsh@projectdiscoveryio/interactsh-cli@prismicio/mocks@monaxlabs/aspen-sdk@monaxlabs/cambium@monaxlabs/gen@monaxlabs/phloem@navch/codec@mhoc/synthesize@metrika/charts@metrika/elastic-charts@nll/api-codegen-ts@nibus/core@shingo/describe2ts@simspace/trout@sudoplatform/sudo-email@sudoplatform/sudo-entitlements@sudoplatform/sudo-entitlements-admin@sudoplatform/sudo-profiles@sudoplatform/sudo-user@sudoplatform/sudo-virtual-cards@sudoplatform/sudo-virtual-cards-admin@sudoplatform/sudo-virtual-cards-simulator@strong-roots-capital/bybit-api@steepleinc/fp@sylo/io-ts@slicemachine/adapter-next@slicemachine/adapter-nuxt@slicemachine/adapter-nuxt2@slicemachine/manager@slicemachine/adapter-sveltekit@stableness/wabblearena-fp-tsaxd@typedash/typedash@vasily.strelyaev/testcafe-reporter-dashboard-devextreme@vuolen/kirjasto-shared
0.3.5

2 years ago

0.3.4

4 years ago

0.3.3

4 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.4

5 years ago

0.2.3

5 years ago

0.2.2

5 years ago

0.2.1

6 years ago

0.2.0

6 years ago

0.1.3-rc

6 years ago

0.1.2

6 years ago

0.1.1

6 years ago

0.1.0

7 years ago

0.0.1

7 years ago