https://github.com/scalarhq/nominal
🔒 The new way to do types in typescript.
https://github.com/scalarhq/nominal
type-safety types typescript
Last synced: 6 months ago
JSON representation
🔒 The new way to do types in typescript.
- Host: GitHub
- URL: https://github.com/scalarhq/nominal
- Owner: scalarhq
- Created: 2022-07-23T00:36:19.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2023-03-22T22:28:47.000Z (over 2 years ago)
- Last Synced: 2025-03-27T02:11:37.291Z (6 months ago)
- Topics: type-safety, types, typescript
- Language: TypeScript
- Homepage: https://zackoverflow.dev/writing/nominal-and-refinement-types-typescript
- Size: 16.6 KB
- Stars: 262
- Watchers: 1
- Forks: 2
- Open Issues: 4
-
Metadata Files:
- Readme: Readme.md
Awesome Lists containing this project
README
# Nominal
The right way to do types in typescript.## Installation
```bash
npm install nominal-typesyarn 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:
```ts
type Minutes = number
type Seconds = number
const minutesToSeconds = (minutes: Minutes) => minutes * 60const seconds: Seconds = 420
// uh-oh, we can use Minutes and Seconds interchangeably
minutesToSeconds(seconds)
```Nominal types solve this problem
```ts
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(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.
```typescript
type SortedArray = Nominal<'sortedArray', Array>const sort = (arr: Array): SortedArray => arr.sort()
const binarySearch = (
sorted: SortedArray,
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](https://en.wikipedia.org/wiki/Refinement_type)
## Composing types
We can actually make this a bit crazier, we can compose nominal types
```ts
type SortedArray = Nominal<'sortedArray', Array>
const sort = (arr: Array): SortedArray => arr.sort() as SortedArray
const nonEmpty = (arr:Array):NonEmptyArray => arr.filter(Boolean) as NonEmptyArray
type NonEmptyArray> = Nominal<'nonEmptyArray', T>;
type NonEmptySorted = NonEmptyArray>;const binarySearch = (sorted: NonEmptySorted): 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](./examples), 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)](https://kataskeue.com/gdp.pdf)