Skip to content
Type matching library for
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


Type matching library for TypeScript.

TypeScript is doing great job by bringing type safety to JavaScript land, It will save you from writing lots of checks which can be defined as types and executed at compilation time. But all of this is only true while your code users are also in safe environment, from Input to Output, so you functions relying on type safe inputs will not crack.

This library provides constructions to cover your input with type checks and pattern-match on them.


npm install --save typematcher

Usage examples

TypeMatcher library contains 2 main components:

  • type matchers - functions to check value matches a type
  • matching dsl - constructs to map a type A to B using type matchers to refine

TypeMatcher is a type alias for a function returning true if its argument type matches:

type TypeMatcher<T> = (val: any) => val is T

Some type matchers: isString, isNumber, isArrayOf, isTuple1.

Matching DSL consists of few functions: match, caseWhen and caseDefault:

Exhaustive match:

import { match, caseWhen, isString } from "typematcher"

const x: number = match("1" as string | number,
  caseWhen(isNumber, _ => _).
  caseWhen(isString, _ => parseInt(_, 10))

Default case handler:

import { match, caseWhen, isBoolean } from "typematcher"

const x: 1 | 0 = match("2" as string | number,
  caseWhen(isBoolean, _ => _ ? 1 : 0).
  caseWhen(isNumber, _ => _ > 0 ? 1 : 0).
  // string type not covered, default case required
  caseDefault(() => 0)

Composing type matchers:

import {
  match, caseWhen, caseDefault, isValue, hasFields, isString, isOptional, isNumber,
  isEither, isNull
} from 'typematcher'

enum UserRole {
  Member = 0,
  Moderator = 1,
  Admin = 2

type User = {
  name: string,
  role: UserRole,
  age?: number

 * UserRole type matcher
function isUserRole(val: any): val is UserRole {
  switch (val) {
    case UserRole.Member:
    case UserRole.Moderator:
    case UserRole.Admin:
      return true
      return false

const isUser: TypeMatcher<User> = hasFields({
  name: isString,
  role: isUserRole,
  age: isOptional(isNumber)

const user: any = { name: "John", role: 20 }

const u: User | null = match(user,
  caseWhen(isEither(isUser, isNull), _ => _).
  caseDefault(() => null)

Sometimes is simpler to use switch/case but unfortunately not as an expression.

For more examples - check links in documentation section.


Case handlers type variance

Avoid explicitly setting argument type in caseWhen() handler function, let type inferred by compiler. You may set more specific type, but check will bring you more general one and compiler will not fail. This is caused by TypeScript Function Parameter Bivariance feature.

UPD: Typescript v2.6 brings --strictFunctionTypes compiler option and if it's on, for this code:

match(8, caseWhen(isNumber, (n: 10) => "n is 10"))

you will now get this error:

error TS2345: Argument of type '8' is not assignable to parameter of type '10'.

  match(8, caseWhen(isNumber, (n: 10) => "n is 10"))

Use caseDefault at the end

match will execute all cases as provided, so first matching will return, use caseDefault, caseAny last.

New match DSL introduced in typematcher@0.8.0 brought compile-time exhaustivity checking, so this code:

const x: "ten" | "twenty" = match(8 as any, 
  caseWhen(isString, () => "ten")

will fail at compile time with:

error TS2322: Type 'string' is not assignable to type '"ten" | "twenty"'.

  const x: "ten" | "twenty" = match(8 as any,

But you still have to handle default case when any result type is expected (which is highly not recommended), otherwise it may fail with No match error at runtime.

const x: any = match(8 as any, 
  caseWhen(isString, () => "ten").
  caseDefault(() => "twenty")


Perfection is Achieved Not When There Is Nothing More to Add, But When There Is Nothing Left to Take Away

Fork, Contribute, Push, Create pull request, Thanks.


Check latest sources on github:

Pattern matching for typescript blog post.

Funfix binding:

You can’t perform that action at this time.