UNPKG

object-shape-tester

Version:
108 lines (78 loc) 3.7 kB
# object-shape-tester Create types, run-time type requirements, and run-time default values with a single definition. Can be used in tests and at run-time (it does not depend on any testing libraries). Full API docs: https://electrovir.github.io/object-shape-tester # Installation ```sh npm i object-shape-tester ``` # Usage This package allows you to define an object's shape in a manner which can be used for testing objects at run time to make sure they conform to your defined shapes. Because it also generates TS types from your defined shape _and_ a default run-time value from your defined shape, **you will have one single source of truth** for all types, defaults, and shape tests. ## Simple example See this simple example for defining a simple user type: <!-- example-link: src/readme-examples/simple-user-shape.example.ts --> ```TypeScript import {defineShape, isValidShape} from 'object-shape-tester'; const userShapeDefinition = defineShape({ name: 'empty name', id: 0, }); export type User = typeof userShapeDefinition.runtimeType; export const emptyUser = userShapeDefinition.defaultValue; export function isUser(input: unknown): input is User { // you don't NEED to wrap isValidShape in a type guard as it is already a type guard itself return isValidShape(input, userShapeDefinition); } const myUser: User = { name: 'my name', id: 1000, }; ``` From a single object (passed into `defineShape`), we get a type definition, a default value, and an object which can be used for run-time object shape testing. ## Complex example For more complex types, this package provides type specifiers that you can use. The available type specifiers are currently the following: - `or(valueA, valueB, ...)`: for allowing multiple types. This gets converted in TypeScript to a union. - `and(valueA, valueB, ...)`: for creating a combined type. This gets converted in TypeScript to an intersection. - `exact(valueA, valueB, ...)`: requires the provided value to be exactly matched. This gets converted in TypeScript to a literal const type. (Example: instead of a value of `'empty name'` getting converted into a string type, `exact('empty name')` will _only_ allow the value `'empty name'`.) - `enumShape(enumA)`: use this for enum types. - `unknownShape()`: use this to allow any type. Here's a more complex user example that uses all of the above specifiers: <!-- example-link: src/readme-examples/complex-user-shape.example.ts --> ```TypeScript import {and, defineShape, enumShape, exact, isValidShape, or, unknownShape} from 'object-shape-tester'; enum AuthLevel { Basic = 'basic', Admin = 'admin', } const complexUserShapeDefinition = defineShape({ firstName: 'first', middleInitial: or('M', undefined), lastName: 'last', id: 0, tags: and({userTags: ['']}, {creatorTags: ['']}), primaryColor: exact('red', 'green', 'blue'), authLevel: enumShape(AuthLevel), extraDetails: unknownShape(), }); export type ComplexUser = typeof complexUserShapeDefinition.runtimeType; export const emptyComplexUser = complexUserShapeDefinition.defaultValue; export function isComplexUser(input: unknown): input is ComplexUser { // you don't NEED to wrap isValidShape in a type guard as it is already a type guard itself return isValidShape(input, complexUserShapeDefinition); } const myComplexUser: ComplexUser = { firstName: 'my first', middleInitial: undefined, lastName: 'last name', id: 1000, tags: { userTags: [], creatorTags: [], }, primaryColor: 'blue', authLevel: AuthLevel.Admin, extraDetails: { whatever: 'you want', }, }; ```