UNPKG

type-definitions

Version:
404 lines (271 loc) 9.49 kB
# type-definitions The purpose of this package is to allow for defining type/object structure in an easily recognizable JSON format. An example definition might look something like: ```javascript import { defineType } from 'type-definitions'; const myTypeDefinition = defineType({ foo: String, bar: Number, baz: { test: Boolean, something: [String] } }) ``` It also offers validation of values based on those definitions: ```javascript import { defineType } from 'type-definitions'; const aNumber = defineType(Number); aNumber.isOfType(2); // true aNumber.isOfType("test"); // false const arrayOfStringsOrNumbers = defineType([String, Number]); arrayOfStringsOrNumbers.isOfType([1, "test"]); // true arrayOfStringsOrNumbers.isOfType([1, "test", true]); // false const complexObject = defineType({ a: Number, b: String, c: { d: [String], e: Boolean } }); complex.isOfType({ a: 2, b: "test", c: { d: ["some", "value"], e: true } }); // true complex.isOfType({ a: 2, b: "test", c: { d: ["some", "value"], e: "true" } }); // false (a.e !== Boolean) ``` Finally, it offers a way to construct objects of a given type and set defaults for that construction: ```javascript import { defineType, defaultValue, types } from 'type-definition'; const defaultString = defineType(String); const fooString = defineType(defaultValue(String, "foo")); const barString = types.String.withDefault("bar"); defaultString.create(); // '' fooString.create() // 'foo' barString.create() // 'bar' barString.create("some other string") // 'some other string' barString.create(2) // throws error, invalid type const customObject = types.Object.withDefinition({ a: String, b: types.Number.withDefault(5), c: { d: Boolean, e: defaultValue(Boolean, true) } }) customObject.create() // { a: '', b: 5, c: { d: false, e: true } } customObject.create({ a: 'test', c: { d: true }}); // { a: 'test', b: 5, c: { d: true, e: true } } ``` ## `defineType` This function will process the input and return the representation as a class with an `isOfType` static function. It is primarily for coercing native representations, and will pass through the package-defined types. Therefore it's always good to wrap your definitions in this so that they will support as much definition styles as possible. ## Types ### String Validates true for string values (ie `"test"`). Default value: `""` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const aString = defineType(types.String); ``` This also supports coercion from native `String`: ```javascript const aString = defineType(String); ``` ### Number Validates true for number values (ie `1`, `1.23`, `Infinity`, `NaN`, `1.0003e+23`). Default value: `0` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const aNumber = defineType(types.Number); ``` This also supports coercion from native `Number`: ```javascript const aNumber = defineType(Number); ``` ### Boolean Validates true for boolean values (ie `true`, `false`) Default value: `false` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const aBool = defineType(types.Boolean); ``` This also supports coercion from native `Boolean`: ```javascript const aBool = defineType(Boolean); ``` ### Array Validates true for any array (ie `[]`, `["test"]`, `["test", 2, true]`) Default value: `[]` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const anArray = defineType(types.Array); ``` This also supports coercion from native `Array` or empty Array literal (`[]`): ```javascript const anArray = defineType(Array); const anotherArray = defineType([]); ``` ### Array.ofType(type) Validates true for any array that matches type, including empty arrays (ie for `types.Array.ofType(type.String)`, `[]` or `["test"]`) You can also make an of Array of multiple types which will set the type to a Union of the types supplied Default value: `[]` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const anArrayOfStrings = defineType(types.Array.ofType(types.String)); ``` This also supports coercion from an Array literal with types as members (`[String]`, `[String, Number]`): ```javascript const anArrayOfStrings = defineType([String]); const anArrayOfStringsOrNumbers = defineType([String, Number]); ``` ### Object Validates true for an object (`{}`, `new class Test {}`). Does not match `null` or arrays. Default value: `{}` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const anObject = defineType(types.Object); ``` This also supports coercion from native `Object` and an empty object literal (`{}`)"" ```javascript const anObject = defineType(Object); const anotherObject = defineType({}); ``` ### Object.withDefinition(objectDefinition) Validates true for objects that match the defined structure. Note: it will match objects with additional properties not included in the definition by default. You can include the `strict` Default value: default values of individual props Using package type: ```javascript import { types, defineType } from 'type-definitions'; const anObject = defineType(types.Object.withDefinition({ foo: String, bar: Number })); ``` This also supports coercion from an Object literal with members (`{foo: String, bar: Number }`): ```javascript const anObject = defineType({ foo: String, bar: Number }); ``` ### Object.withDefinition(objectDefinition).strict Same as `Object.withDefinition(objectDefinition)` except it also validates that value does not have any additional keys Default value: default values of individual props Using package type: ```javascript import { types, defineType } from 'type-definitions'; const anObject = defineType(types.Object.withDefinition({ foo: String, bar: Number }).strict); ``` There is no native representation of this, however you can import the `strict` function and use that to wrap native types: ```javascript import { defineType, strict } from 'type-definitions'; const aStringOrNull = defineType(strict({ foo: String, bar: Number })); ``` ### Object.keyValuePair(valueType) Validates true for an object where all values match the supplied value type. Default value: `{}` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const aHashOfStrings = defineType(types.Object.keyValuePair(String)); ``` **There is no native representation for this** ### Any Validates true for any value (allows `null` but excludes `undefined`). Default value: `null` Using package type: ```javascript import { types, defineType } from 'type-definitions'; const anyType = defineType(types.Any); ``` **There is no native representation for this** ### Union.ofType(...types) Validates true for any value matches any of the union types. Default value: default value of first type Using package type: ```javascript import { types, defineType } from 'type-definitions'; const unionOfStringAndNumber = defineType(types.Union.ofType(String, Number)); ``` There is no native representation of this, however you can import the `unionOf` function and use that to wrap native types: ```javascript import { defineType, unionOf } from 'type-definitions'; const unionOfStringAndNumber = unionOf(String, Number) ``` ### Optional All built in types include can be modified to validate for null/undefined by appending the `.optional` modifier Default value: `null` unless user specified Using package type: ```javascript import { types, defineType } from 'type-definitions'; const aStringOrNull = defineType(types.String.optional); ``` There is no native representation of this, however you can import the `optional` function and use that to wrap native types: ```javascript import { defineType, unionOf } from 'type-definitions'; const aStringOrNull = optional(String) ``` ### Custom Classes Custom classes can be supported by providing a `static isOfType(val)` method on your class. It will leverage whatever logic you put in this method for validation Default value: `Object.create(CustomClass)` ```javascript class MyClass { static isOfType(val) { return val.__type === "myType" } get __type() { return "myType"; } } class SomeOtherClass { get __type() { return "!!!"; } } defineType(MyType).isOfType(new SomeOtherClass()); // false ``` _If you use a class that **does not** define `state isOfType(val)` then `isOfType` will fall back to using `instanceof` for validation_ ## Type.withDefault() / Type.create() Taking an exisitng type and calling `.create(val)` on it will construct an instance of of that type with the given value (assuming the provided value validates). If no value is provided it will construct an object with the _default_ value of an object (see defaults above) If you would like to change the default value of an object there is a `withDefault()` static on all type extending from `BaseType` (or coerced via `defineType`) which takes a default value, validates it against the type and if it's value uses that as the default construction value. Additionally there is a `defaultValue(type, val)` method exported for use in wrapping native types For objects, you can provide a partial value to `.create()` and it will use defaults to fill in other properties as it is able to.