0.1.0 • Published 1 year ago

@gapstack/light-type v0.1.0

Weekly downloads
-
License
-
Repository
-
Last release
1 year ago

light-type

Experimental runtime type safety solution with the following goals:

  • Typescript first, performant for both code-intelligence and at runtime. If Typescript can do something natively, prefer utilising that.
  • Be 1-1 compatible with typescript type system
  • Types should be inferable and have both inputs and outputs
  • Integrate well with tools like tRPC
  • Be comfortable for a Zod user to move over from, most features should be a drop-in replacement

This project is very much a work in progress, the TODOs are even on this readme to prove it!

# Choose your package manager
npm install @gapstack/light-type
yarn add @gapstack/light-type
pnpm add @gapstack/light-type

Usage:

// Most APIs are the same as zod
import { lt } from '@gapstack/light-type'

// Basic types are essentially identical
const obj = lt.object({
  num: lt.number().default(0),
  str: lt.string().optional(),
  bool: lt.boolean(),
  literal: lt.literal('foo')
})

// These are all essentially the same but with much better editor performance
const maskedObject = obj.merge().extend().omit().pick()

//
// Others have been consolidated or changed

// lt.pipe replaces `.preprocess` and accepts an arbitrary chain of functors/types
lt.pipe(unknownValue => String(unknownValue), lt.string())

// pipe also replaces .transform and the .refine family. it's the same as lt.pipe for usage
lt.string().pipe()

// Pipe can also raise validation errors, which will get aggregated up and throw by .parse
lt.string().pipe((numStr, ctx) => {
  const num = parseInt(numStr)
  if (!isNaN(num)) {
    return num
  }

  ctx.addIssue({
    // There are some pre-set type literals but you can pass any string
    type: 'custom_nan',
    message: 'Custom NaN Error',
    value: numStr
  })
})

// Some pipe validators are bundled out of the box
import { assert, strings, numbers } from '@gapstack/light-type/src/lib/validators'
lt.string().pipe(assert(v => v === "test", "String should have been 'test'"))

// .parse is the same
lt.string().parse("Hello world")

// But .check is new and works the same, except it's statically typed with the input
lt.string().check("Check knows this is a string")

// Also .satisfiesInput is new for when you're building for compatibility with types you don't control
lt.string().satisfiesInput<number>() // compile-error

There are some features missing still which are important. See the todo list below for information.

TODO list:

  • Documentation
  • Custom error messages for validation errors
  • Structure of classes, options:
  • Look at alternative merge/extends patterns, given benchmark differences with "spread" on merge/extend
  • Object Discriminated Unions - later, they auto-discriminate just not at great runtime performance
  • .extend should accept a record type
    • maybe implement .open to 'open' a type for extension?
  • String Template Literals
  • Set up Runtime benchmarks
    • Consider changing all chainable methods to prototype methods if performance can be improved
  • Calculated values
  • Bundled parsers or a recommended library/pattern
    • ISO Date parsing

Docs on performance:

0.1.0

1 year ago

0.0.20

1 year ago

0.0.21

1 year ago

0.0.22

1 year ago

0.0.23

1 year ago

0.0.10

1 year ago

0.0.11

1 year ago

0.0.12

1 year ago

0.0.13

1 year ago

0.0.14

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.15

1 year ago

0.0.9

1 year ago

0.0.16

1 year ago

0.0.8

1 year ago

0.0.17

1 year ago

0.0.18

1 year ago

0.0.19

1 year ago

0.0.5

1 year ago

0.0.4

1 year ago

0.0.7

1 year ago

0.0.6

1 year ago

0.0.1

1 year ago