Giter VIP home page Giter VIP logo

nominal's Introduction

Nominal

The right way to do types in typescript.

Installation

npm install nominal-types

yarn install nominal-types

pnpm install nominal-types

Usage

Basic

The most immediate benefit of nominal types is preventing confusion between two types. In regular Typescript you run into this problem:

type Minutes = number
type Seconds = number
const minutesToSeconds = (minutes: Minutes) => minutes * 60

const seconds: Seconds = 420
// uh-oh, we can use Minutes and Seconds interchangeably
minutesToSeconds(seconds)

Nominal types solve this problem

import { Nominal, nominal } from 'nominal-types';

type Minutes = Nominal<'Minutes', number>;
type Seconds = Nominal<'Seconds', number>;

const minutesToSeconds = (minutes: Minutes) => minutes * 60

// You can directly type cast or use nominal.make
const seconds = nominal.make<Seconds>(420)
const minutes = 1337 as Minutes

// doesn't work, yay type safety
minutesToSeconds(seconds)
// does work!
minutesToSeconds(minutes)

Another example

You can use nominal types to give your code even better type-safety guarantees.

This goes beyond just type-safety, it's a performance optimization: once you know the array is sorted, you never have to sort it again. This is enforcing that at a type level.

type SortedArray<T> = Nominal<'sortedArray', Array<T>>

const sort = <T>(arr: Array<T>): SortedArray<T> => arr.sort()

const binarySearch = <T>(
  sorted: SortedArray<T>,
  search: T
): number | undefined  => {
    /* ... */
}

const regularArray = [1, 7, 2, 3, 6, 9, 10, 4, 5]
// won't work
binarySearch(regularArray, 2)
// will work
binarySearch(sort(regularArray), 3)

This is also known as Refinement types

Composing types

We can actually make this a bit crazier, we can compose nominal types

type SortedArray<T> = Nominal<'sortedArray', Array<T>>

const sort = <T>(arr: Array<T>): SortedArray<T> => arr.sort() as SortedArray<T>

const nonEmpty = <T>(arr:Array<T>):NonEmptyArray<T> => arr.filter(Boolean) as NonEmptyArray<T>

type NonEmptyArray<K, T extends Array<K>> = Nominal<'nonEmptyArray', T>;
type NonEmptySorted<T> = NonEmptyArray<T, SortedArray<T>>;

const binarySearch = <T>(sorted: NonEmptySorted<T>): T => {
  let foo = sorted[0]
  return foo
}

// won't work
binarySearch(regularArray)
// still won't work
binarySearch(sort(regularArray))

binarySearch(nonEmpty(sort(regularArray)))

Examples

More examples in examples folder, you can also see them typed on replit.

Example Link
basic https://replit.com/@CryogenicPlanet/Nominal#basic.ts
sorting https://replit.com/@CryogenicPlanet/Nominal#sort.ts
composing https://replit.com/@CryogenicPlanet/Nominal#composing.ts
safeRecords https://replit.com/@CryogenicPlanet/Nominal#safeRecord.ts

Credits

You can read more about this https://zackoverflow.dev/writing/nominal-and-refinement-types-typescript

Inspiration from Ghosts of Departed Proofs (Functional Pearl)

nominal's People

Contributors

cryogenicplanet avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

jthodge

nominal's Issues

[Question]What's the different between this project and ts-opaque ?

This project seems to be a simplified version of that one, from what I read you seem to be using similar approaches to make the magic happen. I haven't read the entire code so I am probably wrong.
But anyway can the nominal type be used as a better/newer/shorter/lighter alternative to opaque type, since they are conceptually similar ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.