Socket
Socket
Sign inDemoInstall

simple-runtypes

Package Overview
Dependencies
0
Maintainers
1
Versions
25
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    simple-runtypes

I said I want **SIMPLE** runtypes. Just functions that validate and return data. Combine them into complex types and Typescript knows their structure. Thats how runtypes work.


Version published
Maintainers
1
Install size
271 kB
Created

Changelog

Source

6.0.1

  • fix: rename useRuntype to use

Readme

Source

npm version unit-tests npm-publish

Preface

I said I want SIMPLE runtypes. Just functions that validate and return data. Combine them into complex types and Typescript knows their structure. Thats how runtypes work.

Install

npm install simple-runtypes or yarn add simple-runtypes

Example

  1. Define the Runtype:
import * as st from 'simple-runtypes'

const userRuntype = st.record({
    id: st.integer(),
    name: st.string(),
    email: st.optional(st.string()),
})

now, ReturnType<typeof userRuntype> is equivalent to

interface {
    id: number,
    name: string,
    email?: string
}
  1. Use the runtype to validate untrusted data
userRuntype({id: 1, name: 'matt'})
// => {id: 1, name: 'matt'}

userRuntype({id: 1, name: 'matt', isAdmin: true})
// throws a st.RuntypeError 'invalid field 'isAdmin' in data

You can also use a runtype without throwing errors:

st.use(userRuntype, {id: 1, name: 'matt'})
// => {ok: true, result: {id: 1, name: 'matt'}}

st.use(userRuntype, {id: 1, name: 'matt', isAdmin: true})
// => {ok: false, error: FAIL}

st.getFormattedError(FAIL)
// => 'invalid keys in record ["c"] at `<value>` in `{"a":1,"b":"as","c":false}`'

Not throwing errors is way more efficient but less convenient as you always have to check the resulting type.

Why?

Why should I use this over the plethora of other runtype validation libraries available?

  1. Written in and for Typescript
  2. Strict by default
  3. Supports efficient discriminated unions
  4. Frontend-friendly (no eval, small footprint, no dependencies)
  5. Fast (of all non-eval based libs, only one is faster according to the benchmark)

Benchmarks

@moltar has done a great job comparing existing runtime typechecking libraries in moltar/typescript-runtime-type-benchmarks

Documentation

Intro

A Runtype is a function that:

  1. receives an unknown value
  2. returns that value or a copy if all validations pass
  3. throws a RuntypeError when validation fails or returns ValidationResult when passed to use
interface Runtype<T> {
    (v: unknown) => T
}

Runtypes are constructed by calling factory functions. For instance, string creates and retuns a string runtype. Check the factory functions documentation for more details.

Usage Examples

Strict Property Checks

When using record, any properties which are not defined in the runtype will cause the runtype to fail:

const strict = st.record({name: st.string()})

strict({name: 'foo', other: 123})
// => RuntypeError: Unknown attribute 'other'

To ignore single properties, use ignore, unknown or any:

const strict = st.record({name: st.string(), other: st.ignore()})

strict({name: 'foo', other: 123})
// => {name: foo, other: undefined}

Use sloppyRecord to only validate known properties and remove everything else:

const sloppy = st.sloppyRecord({name: st.string()})

strict({name: 'foo', other: 123, bar: []})
// => {name: foo}

Using any of record or sloppyRecord will keep you safe from any __proto__ injection or overriding attempts.

Optional Properties

Use the optional runtype to create optional properties:

const squareConfigRuntype = st.record({
  color: st.optional(st.string()),
  width?: st.optional(st.number()),
})
Nesting

Collection runtypes such as record, array, tuple take runtypes as their parameters:

const nestedRuntype = st.record({
  name: st.string(),
  items: st.array(st.recorcd({ id: st.integer, label: st.string() })),
})

nestedRuntype({
  name: 'foo',
  items: [{ id: 3, label: 'bar' }],
}) // => returns the same data
Discriminating Unions

Simple-runtypes supports Discriminating Unions via the union runtype.

The example found in the Typescript Handbook translated to simple-runtypes:

const networkLoadingState = st.record({
  state: st.literal('loading'),
})

const networkFailedState = st.record({
  state: st.literal('failed'),
  code: st.number(),
})

const networkSuccessState = st.record({
  state: st.literal('success'),
  response: st.record({
    title: st.string(),
    duration: st.number(),
    summary: st.string(),
  })
})

const networdStateRuntype = st.union(
  networkLoadingState,
  networkFailedState,
  networkSuccessState,
)

type NetworkState = ReturnType<networkStateRuntype>

Finding the runtype to validate a specific discriminating union with is done efficiently with a Map.

Reference

Basic runtypes that match TS / Javascript types:

Meta runtypes

Objects and Array Runtypes

Advanced Runtypes

Roadmap / Todos

  • rename sloppyRecord to record.sloppy because I need the "sloppy"-concept for other runtypes too: e.g. nullable.sloppy - a Runtype<T | null> that also accepts undefined which is useful to slowly add new nullable fields to existing json database records
  • improve docs:
    • preface: what is a runtype and why is it useful
    • why: explain or link to example that shows "strict by default" and "efficient discriminating unions"
    • show that simple-runtypes is feature complete because it can
      1. express all typescript types
      2. is extendable with custom runtypes (add documentation)
    • add small frontend and backend example projects that show how to use simple-runtypes in production
  • test types with tsd
  • add missing combinators: partial, required
  • add other combinators like partial, required, ...

FAQs

Last updated on 05 Nov 2020

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc