Pattern matching is a feature built in into many programming languages. Sadly it's not included in JavaScript nor TypeScript. It's like a switch
statement on steroids, that lets you write a more declarative code.
This library aims to implement a pattern matching system that works well with other aspects of TS. It uses Builder Pattern to get all the cases and evaluate them. The default case is mandatory.
Install it using npm (or yarn).
npm install @safe-ts/pattern
It can be imported then in your *.ts files.
import match, { AnyNumber, AnyString } from '@safe-ts/pattern'
// (...)
match(x)
.case(AnyNumber, () => '...')
.case(AnyString, () => '...')
.default(() => '...')
import scala.util.Random
val x: Int = Random.nextInt(10)
x match {
case 0 => "zero"
case 1 => "one"
case 2 => "two"
case _ => "other"
}
patternMatching : Int -> String
patternMatching x =
case x of
0 -> "zero"
1 -> "one"
2 -> "two"
_ -> "other"
const x = Math.floor(Math.random() * 10);
match(x)
.case(0, () => 'zero')
.case(1, () => 'one')
.case(2, () => 'two')
.default(() => 'other')
const result = match(5)
.case(1, () => 'one')
.case(3, () => 'three')
.case(5, () => 'five')
.default(x => `The value is ${x}`)
result // 'five'
const result = match(anObject)
.case({ loading: true }, () => 'Loading...')
.case({ data: true }, () => 'Data received')
.default(() => 'Default state')
const result = match(anObject)
.case({ loading: true }, () => 'Loading...')
.case({ data: AnyObject }, () => 'Data received')
.case({ error: AnyObject }, () => 'Error!')
.default(() => 'Default state')
When parsing JSON strings we do not know if the result will be correctly typed.
interface User {
name: string
age: number
}
const jsonString = '{ "definetly": "not an user" }'
const user = JSON.parse(jsonString) as User
user.name // runtime boom
interface User {
name: string
age: number
}
const jsonString = '{ "definetly": "not an user" }'
const user = match<User | null>(JSON.parse(jsonString))
.case({ name: AnyString, age: AnyNumber }, (user: unknown) => user as User)
.default(() => null)
user && user.name // user will be null if the structure is not right, otherwise it's always guaranteed to be of User type.