Gathering detailed insights and metrics for simple-runtypes
Gathering detailed insights and metrics for simple-runtypes
npm install simple-runtypes
Typescript
Module System
77.3
Supply Chain
99
Quality
76
Maintenance
100
Vulnerability
100
License
TypeScript (100%)
Love this project? Help keep it running — sponsor us today! 🚀
Total Downloads
593,835
Last Day
147
Last Week
953
Last Month
3,342
Last Year
163,950
MIT License
116 Stars
218 Commits
5 Forks
4 Watchers
5 Branches
5 Contributors
Updated on Dec 21, 2024
Minified
Minified + Gzipped
Latest Version
7.1.3
Package Id
simple-runtypes@7.1.3
Unpacked Size
320.70 kB
Size
84.23 kB
File Count
45
Published on
Feb 22, 2023
Cumulative downloads
Total Downloads
Last Day
38.7%
147
Compared to previous day
Last Week
7.3%
953
Compared to previous week
Last Month
114.8%
3,342
Compared to previous month
Last Year
-54.2%
163,950
Compared to previous year
I said I want SIMPLE runtypes. Just functions that validate and return data. Combine them into complex types and TypeScript knows their structure. That's how runtypes work.
npm install simple-runtypes
or yarn add simple-runtypes
1import * as st from 'simple-runtypes' 2 3const userRuntype = st.record({ 4 id: st.integer(), 5 name: st.string(), 6 email: st.optional(st.string()), 7})
now, ReturnType<typeof userRuntype>
is equivalent to
1interface { 2 id: number, 3 name: string, 4 email?: string 5}
1userRuntype({id: 1, name: 'matt'}) 2// => {id: 1, name: 'matt'} 3 4userRuntype({id: 1, name: 'matt', isAdmin: true}) 5// throws an st.RuntypeError: "invalid field 'isAdmin' in data"
Invoke a runtype with use
to get a plain value back instead of throwing errors:
1st.use(userRuntype, {id: 1, name: 'matt'}) 2// => {ok: true, result: {id: 1, name: 'matt'}} 3 4st.use(userRuntype, {id: 1, name: 'matt', isAdmin: true}) 5// => {ok: false, error: FAIL} 6 7st.getFormattedError(FAIL) 8// => 'invalid keys in record: ["isAdmin"] at `<value>` in `{"id":1,"name": "matt", ... }`'
Not throwing errors is way more efficient and less obscure. Throwing errors and catching them outside is more convenient.
Why should I use this over the plethora of other runtype validation libraries available?
eval
, a small footprint and no dependencies@moltar has done a great job comparing existing runtime type-checking libraries in moltar/typescript-runtime-type-benchmarks.
@pongo has benchmarked simple-runtypes
against io-ts
in pongo/benchmark-simple-runtypes.
A Runtype
is a function that:
RuntypeError
when validation fails
or returns ValidationResult
when passed to use
1interface Runtype<T> { 2 (v: unknown) => T 3}
Runtypes are constructed by calling factory functions.
For instance, string
creates and returns a string runtype.
Check the factory functions documentation for more details.
When using record
, any properties which are not defined in the runtype will cause the runtype to fail:
1const strict = st.record({name: st.string()}) 2 3strict({name: 'foo', other: 123}) 4// => RuntypeError: Unknown attribute 'other'
To ignore single properties, use ignore
, unknown
or any
:
1const strict = st.record({name: st.string(), other: st.ignore()}) 2 3strict({name: 'foo', other: 123}) 4// => {name: foo, other: undefined}
Use sloppyRecord
to only validate known properties and remove everything else:
1const sloppy = st.sloppyRecord({name: st.string()}) 2 3sloppy({name: 'foo', other: 123, bar: []}) 4// => {name: foo}
Using any of record
or sloppyRecord
will keep you safe from any __proto__
injection or overriding attempts.
Use the optional
runtype to create optional properties:
1const squareConfigRuntype = st.record({ 2 color: st.optional(st.string()), 3 width?: st.optional(st.number()), 4})
Collection runtypes such as record
, array
, tuple
take runtypes as their parameters:
1const nestedRuntype = st.record({ 2 name: st.string(), 3 items: st.array(st.record({ id: st.integer, label: st.string() })), 4}) 5 6nestedRuntype({ 7 name: 'foo', 8 items: [{ id: 3, label: 'bar' }], 9}) // => returns the same data
simple-runtypes
supports Discriminating Unions via the union
runtype.
The example found in the TypeScript Handbook translated to simple-runtypes
:
1const networkLoadingState = st.record({ 2 state: st.literal('loading'), 3}) 4 5const networkFailedState = st.record({ 6 state: st.literal('failed'), 7 code: st.number(), 8}) 9 10const networkSuccessState = st.record({ 11 state: st.literal('success'), 12 response: st.record({ 13 title: st.string(), 14 duration: st.number(), 15 summary: st.string(), 16 }) 17}) 18 19const networdStateRuntype = st.union( 20 networkLoadingState, 21 networkFailedState, 22 networkSuccessState, 23) 24 25type NetworkState = ReturnType<typeof networkStateRuntype>
Finding the runtype to validate a specific discriminating union with is done efficiently with a Map
.
Write your own runtypes as plain functions, e.g. if you want to turn a string into a BigInt
:
1const bigIntStringRuntype = st.string({match: /^-?[0-9]+n$/}) 2 3const bigIntRuntype = st.runtype((v) => { 4 const stringCheck = st.use(bigIntStringRuntype, v) 5 6 if (!stringCheck.ok) { 7 return stringCheck.error 8 } 9 10 return BigInt(stringCheck.result.slice(0, -1)) 11}) 12 13bigIntRuntype("123n") // => 123n 14bigIntRuntype("2.2") // => error: "expected string to match ..."
Basic runtypes that match JavaScript/TypeScript types:
Meta runtypes:
Objects and Array Runtypes:
Combinators:
union
intersection
omit
pick
partial
get
- similar to Type[key]Shortcuts:
size
- a meta-runtype that imposes a size limit on types, maybe via convert-to-json and .length on the value passed to itstringLiteralUnion
to literals
or literalUnion
and make it work
on all types that literal
acceptssimple-runtypes
is feature complete because it can
simple-runtypes
in productionRuntype
and InternalRuntype
and type runtype internals
(see this comment)No vulnerabilities found.
Reason
no binaries found in the repo
Reason
no dangerous workflow patterns detected
Reason
license file detected
Details
Reason
9 existing vulnerabilities detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
Found 2/22 approved changesets -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Score
Last Scanned on 2025-02-10
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More