Skip to content

Ensure type safety in your JavaScript code with compilation-based type checking solution.

License

Notifications You must be signed in to change notification settings

syarul/closet-type

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

closet-type

NPM Version closet-type CI Coverage Status

Ensure type safety in your JavaScript code with compilation-based type checking solution.

Introduction

This module provides an implementation of type checking similar to Joi or prop-types. Its main purpose is to check types during the compilation phase, thereby allowing you to catch errors before moving to production. Once you have prepared your code, you can use the compiler. Some of the advantages of using this module are:

  • You can use objects or plain strings to define rules or interfaces
  • You can use classes, or extend them and validate them
  • The module compiles clean versions of your code from JS to JS
  • The module supports most types defined in the Lodash Lang methods, as long as they take a single argument

Here's the first example to get you started. Try it here—no build step required!

Usage

By default, performing type checking often requires hardcoding type validation, which can clutter your code with unnecessary and redundant lines.

const add = (a, b) => {
  if (typeof a !== 'number' && typeof b !== 'number') { // check type
    throw new TypeError('Wrong argument types')         // check type
  }                                                     // check type
  return a + b
}

export default add

With closet-type, you can perform your checking in the wrapper itself, without having to pass it to the actual function yet.

import { Closet } from 'closet-type'

const closet = new Closet()

const add = (a, b) => a + b

export default closet.execType(add)('number', 'number')

Experience the seamless transformation of your code after compiling with the compiler.

const add = (a, b) => a + b

export default add

Types

Supported types are:-

  • arguments // lodash
  • array // lodash
  • arrayBuffer // lodash
  • arrayLike // lodash
  • arrayLikeObject // lodash
  • boolean // lodash
  • buffer // lodash
  • date // lodash
  • element // lodash
  • empty // lodash
  • error // lodash
  • finite // lodash
  • function // lodash
  • integer // lodash
  • length // lodash
  • map // lodash
  • NaN // lodash
  • native // lodash
  • nil // lodash
  • null // lodash
  • number // lodash
  • object // lodash
  • objectLike // lodash
  • plainObject // lodash
  • RegExp // lodash
  • safeInteger // lodash
  • set // lodash
  • string // lodash
  • symbol // lodash
  • typedArray // lodash
  • undefined // lodash
  • weakMap // lodash
  • weakSet // lodash
  • promise // check if it a promise

To add new types

const closetWithNewType = new Closet()
  .addTypes({
    uuid: function (uuid) { // new uuid type is now available
      return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(uuid) 
    }
  })
  .addRules({ _id: { type: 'uuid' } }) 

or

import { addNewTypes, typed } from 'closet-type'

addNewTypes({ mongoId: (id) => /^[a-f\d]{24}$/i.test(id) })

typed('mongoId')('5f45f935887dbf37e853e7d1')(console.log) // 5f45f935887dbf37e853e7d1

Usage with rule definition

import { Closet } from 'closet-type'

const rule = {
  name: { type: 'string', required: true },
  age: { type: 'number', required: true, min: 18 },
  email: { type: 'string', required: true, format: /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ },
  address: {
    type: 'object',
    required: true,
    properties: {
      city: { type: 'string', required: true },
      state: { type: 'string', required: true },
      zip: { type: 'string', required: true, length: 5 }
    }
  }
}

const closet = new Closet()

closet.addRules(rule)

const data = {
  name: 'John',
  age: 30,
  email: 'john@example.com',
  address: {
    city: 'New York',
    state: 'NY',
    zip: '10001'
  }
}

const fn = (d) => d

closet.execType(fn)(data) // data

For more usage cases, check the test folder.

Compiling

Streamline your compilation process and save time with the webpack loader https://github.com/syarul/webpack-closet-type

npm install webpack-closet-type

To manually compile use the compiler executable

npm install -g closet-type

type closet-compile -h

-h, --help             output usage information
-V, --version          output the version number
-f, --file <name>      file target to compile
-s, --string <name>    read source from string in base64
-e, --encoding <name>  read source from string require encoding, default to utf-8
-o, --output <name>    file to output into

You can use stdin cat somefile.js | closet-compiler, you can also use a base64 string input closet-compile -s VGhpcyBpcyBhIFVURi04IHN0cmlu.... For example type closet-compile -f file.closet.js -o output.js to compile, without output parameter it will log the output to stdout/console

// sample.closet.js
import { Closet } from 'closet-type'

const closet = new Closet()

closet.execType(console.log)('number')(7)

const foo = {
  bar: 1
}

const closet2 = new Closet()

closet2.addRules({
  bar: { type: 'number' }
})

closet2.execType(console.log)(foo)

const cc = new Closet()

const rule = {
  foo: { type: 'string' }
}
cc.addRules(rule)
cc.execType(console.log)({ foo: 'hello' })

will get compiled into

// sample.closet.js

console.log(7)

const foo = {
  bar: 1
}

console.log(foo)

console.log({ foo: 'hello' })

About

Ensure type safety in your JavaScript code with compilation-based type checking solution.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages