Skip to content

Lchemist/TypeGuards

Repository files navigation

TypeGuards

build Coverage Status NPM semantic-release Commitizen friendly Conventional Changelog

Runtime type checking library for TypeScript & JavaScript.

✨ Features

  • Provides runtime type validation.
  • Can derive static type from any type guard, thus types are never out of sync.
  • Supports nested type guards.
  • Supports almost all JS data types, including Promise, Proxy, DataView and typed arrays.
  • Package has 0 dependency.

πŸ“¦ Installation

# npm
npm install @typeguards/core
# yarn
yarn add @typeguards/core

πŸ”¨ Usage

Basics

import T from '@typeguards/core'

T.Number.validates(1) // true
T.Number.validates('1') // false
T.Optional(T.String).validates('1') // true
T.Optional(T.String).validates(undefined) // true
T.Optional(T.String).validates(1) // false

// Custom type guard
const Range = T.Number.config({
  // Custom validation function
  validate: value => typeof value === 'number' && value > 0 && value < 3,
})
Range.validate(0) // false
Range.validate(1) // true
Range.validate(2) // true
Range.validate(3) // false

Schema

import type { Static } from '@typeguards/core'
import T, { createSchema } from '@typeguards/core'

const Age = T.Number.config({ validate: v => typeof v === 'number' && v >= 0 })

// Custom schema
const JobSchema = T.Schema({
  title: T.String,
  salary: T.Nullable(T.Number),
})

// Use closure to use type guard directly & prevent naming conflicts with JS built-in objects
const PersonSchema = createSchema(({ Boolean, String, Number, Array, Optional, Union }) => ({
  name: String,
  age: Age,
  alive: Boolean,
  address: Optional(String),
  // Support complex nested type guard
  favorites: Array(Union(String, Number)),
  // Support nested schema
  job: JobSchema,
}))

// Support static type derivation, thus type is never out of sync
const person: Static<typeof PersonSchema> = {
  name: 'John Doe',
  age: 23,
  alive: true,
  address: undefined,
  favorites: ['cat', 'dog', 7],
  job: {
    title: 'Dreamer',
    salary: null,
  },
}

PersonSchema.validate(person) // true
PersonSchema.validate({ ...person, address: undefined }) // true, because address is optional
PersonSchema.validate({ ...person, name: undefined }) // false
PersonSchema.validate({ ...person, age: '23' }) // false

const CatSchema = T.Partial(T.Pick(PersonSchema, ['name', 'age', 'alive']))
// Equivalent to Partial<Pick<PersonType, 'name' | 'age' | 'alive'>>
type Cat = Static<typeof CatSchema>

CatSchema.validate(person) // false
CatSchema.validate({ name: 'Baby', age: undefined }) // true

// Retrieve Schema definition
const catDefinition = CatSchema.definition() // { name: String, age: Age, alive: Boolean }
// Retrieve Indexed access type definition, which is a type guard in this case
const CatName = CatSchema.definition('name') // T.String
CatName.validate('str') // true
catDefinition.name.validate('str') // true

Transformer (Experimental Feature)

import T from '@typeguards/core'

// Customize transformation function
const Name = T.String.config({ transform: val => `${val} Jr.` })
const Alive = T.Boolean.config({ transform: val => val ?? true })
const Person = T.Partial(T.Schema({ name: Name, alive: Alive }))

const john = { name: 'John' }
Person.validate(john) // true
const johnJr = Person.transform(john) // { name: 'John Jr.', alive: true }

πŸ›‘οΈ List of type guards

name description
Boolean
StringBoolean "true" | "TRUE" | "false" | "FALSE" | "1" | "0"
Number
NaN NaN
PositiveNumber A number value that's greater than 0
NegativeNumber A number value that's less than 0
BigInt
PositiveBigInt A BigInt value that's greater than 0
NegativeBigInt A BigInt value that's less than 0
StringNumber A string whose value is a number, such as "0", "-1", "3.333"
String
NonEmptyString A string that's not empty even after trimming
Symbol
Undefined undefined
Null null
Object An object (Any object will qualify as long as typeof obj === 'object')
RegExp
Map
WeakMap
Set
WeakSet
Promise
Proxy
Date
StringDate A correctly formatted date string, such as "1996-07-23", "1996/07/23", "1996 Jul", "1996"
Array
StringArray A string whose value is an array separated by delimiter "," (delimiter is customizable)
ArrayBuffer
SharedArrayBuffer
DataView
Int8Array
Uint8Array
Uint8ClampedArray
Int16Array
Uint16Array
Int32Array
Uint32Array
Float32Array
Float64Array
BigInt64Array
BigUint64Array
Function A function
Schema A plain object
Optional T | undefined
Nullable T | null
Never Equivalent of TypeScript never type
Unknown Equivalent of TypeScript unknown type
Any Equivalent of TypeScript any type
Record Equivalent of TypeScript Record type
Partial Equivalent of TypeScript Partial type
Required Equivalent of TypeScript Required type
Pick Equivalent of TypeScript Pick type
Omit Equivalent of TypeScript Omit type
NonNullable Equivalent of TypeScript NonNullable type
Union Equivalent of TypeScript union type
Const Equivalent of TypeScript const assertion
GeneratorFunction Requires ES6/ES2015 or later
Generator Requires ES6/ES2015 or later
AsyncFunction Requires ES8/ES2017 or later

πŸ“œ License

Apache License 2.0