io-ts
Advanced tools
Comparing version 2.1.3 to 2.2.0
@@ -17,2 +17,7 @@ # Changelog | ||
# 2.2.0 | ||
- **Experimental** | ||
- add `Codec`, `Decoder`, `Encoder`, `Guard`, `Schema`, `Schemable`, `Tree` modules (@gcanti) | ||
# 2.1.3 | ||
@@ -19,0 +24,0 @@ |
@@ -104,4 +104,13 @@ /** | ||
readonly encode: Encode<A, O>; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _A: A; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _O: O; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _I: I; | ||
@@ -167,2 +176,5 @@ constructor( | ||
export declare class NullType extends Type<null> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'NullType'; | ||
@@ -184,2 +196,5 @@ constructor(); | ||
export declare class UndefinedType extends Type<undefined> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'UndefinedType'; | ||
@@ -198,2 +213,5 @@ constructor(); | ||
export declare class VoidType extends Type<void> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'VoidType'; | ||
@@ -215,2 +233,5 @@ constructor(); | ||
export declare class UnknownType extends Type<unknown> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'UnknownType'; | ||
@@ -232,2 +253,5 @@ constructor(); | ||
export declare class StringType extends Type<string> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'StringType'; | ||
@@ -249,2 +273,5 @@ constructor(); | ||
export declare class NumberType extends Type<number> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'NumberType'; | ||
@@ -266,2 +293,5 @@ constructor(); | ||
export declare class BigIntType extends Type<bigint> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'BigIntType'; | ||
@@ -283,2 +313,5 @@ constructor(); | ||
export declare class BooleanType extends Type<boolean> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'BooleanType'; | ||
@@ -300,2 +333,5 @@ constructor(); | ||
export declare class AnyArrayType extends Type<Array<unknown>> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'AnyArrayType'; | ||
@@ -319,2 +355,5 @@ constructor(); | ||
}> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'AnyDictionaryType'; | ||
@@ -337,2 +376,5 @@ constructor(); | ||
export declare class FunctionType extends Type<Function> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'FunctionType'; | ||
@@ -358,2 +400,5 @@ constructor(); | ||
readonly predicate: Predicate<A>; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'RefinementType'; | ||
@@ -403,2 +448,5 @@ constructor(name: string, is: RefinementType<C, A, O, I>['is'], validate: RefinementType<C, A, O, I>['validate'], encode: RefinementType<C, A, O, I>['encode'], type: C, predicate: Predicate<A>); | ||
readonly value: V; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'LiteralType'; | ||
@@ -423,2 +471,5 @@ constructor(name: string, is: LiteralType<V>['is'], validate: LiteralType<V>['validate'], encode: LiteralType<V>['encode'], value: V); | ||
readonly keys: D; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'KeyofType'; | ||
@@ -445,4 +496,10 @@ constructor(name: string, is: KeyofType<D>['is'], validate: KeyofType<D>['validate'], encode: KeyofType<D>['encode'], keys: D); | ||
runDefinition: () => C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'RecursiveType'; | ||
constructor(name: string, is: RecursiveType<C, A, O, I>['is'], validate: RecursiveType<C, A, O, I>['validate'], encode: RecursiveType<C, A, O, I>['encode'], runDefinition: () => C); | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly type: C; | ||
@@ -459,2 +516,5 @@ } | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ArrayType'; | ||
@@ -477,2 +537,5 @@ constructor(name: string, is: ArrayType<C, A, O, I>['is'], validate: ArrayType<C, A, O, I>['validate'], encode: ArrayType<C, A, O, I>['encode'], type: C); | ||
readonly props: P; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'InterfaceType'; | ||
@@ -523,2 +586,5 @@ constructor(name: string, is: InterfaceType<P, A, O, I>['is'], validate: InterfaceType<P, A, O, I>['validate'], encode: InterfaceType<P, A, O, I>['encode'], props: P); | ||
readonly props: P; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'PartialType'; | ||
@@ -558,2 +624,5 @@ constructor(name: string, is: PartialType<P, A, O, I>['is'], validate: PartialType<P, A, O, I>['validate'], encode: PartialType<P, A, O, I>['encode'], props: P); | ||
readonly codomain: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'DictionaryType'; | ||
@@ -592,2 +661,5 @@ constructor(name: string, is: DictionaryType<D, C, A, O, I>['is'], validate: DictionaryType<D, C, A, O, I>['validate'], encode: DictionaryType<D, C, A, O, I>['encode'], domain: D, codomain: C); | ||
readonly types: CS; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'UnionType'; | ||
@@ -610,2 +682,5 @@ constructor(name: string, is: UnionType<CS, A, O, I>['is'], validate: UnionType<CS, A, O, I>['validate'], encode: UnionType<CS, A, O, I>['encode'], types: CS); | ||
readonly types: CS; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'IntersectionType'; | ||
@@ -647,2 +722,5 @@ constructor(name: string, is: IntersectionType<CS, A, O, I>['is'], validate: IntersectionType<CS, A, O, I>['validate'], encode: IntersectionType<CS, A, O, I>['encode'], types: CS); | ||
readonly types: CS; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'TupleType'; | ||
@@ -689,2 +767,5 @@ constructor(name: string, is: TupleType<CS, A, O, I>['is'], validate: TupleType<CS, A, O, I>['validate'], encode: TupleType<CS, A, O, I>['encode'], types: CS); | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ReadonlyType'; | ||
@@ -711,2 +792,5 @@ constructor(name: string, is: ReadonlyType<C, A, O, I>['is'], validate: ReadonlyType<C, A, O, I>['validate'], encode: ReadonlyType<C, A, O, I>['encode'], type: C); | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ReadonlyArrayType'; | ||
@@ -756,2 +840,5 @@ constructor(name: string, is: ReadonlyArrayType<C, A, O, I>['is'], validate: ReadonlyArrayType<C, A, O, I>['validate'], encode: ReadonlyArrayType<C, A, O, I>['encode'], type: C); | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ExactType'; | ||
@@ -839,2 +926,5 @@ constructor(name: string, is: ExactType<C, A, O, I>['is'], validate: ExactType<C, A, O, I>['validate'], encode: ExactType<C, A, O, I>['encode'], type: C); | ||
export declare class NeverType extends Type<never> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'NeverType'; | ||
@@ -859,2 +949,5 @@ constructor(); | ||
export declare class AnyType extends Type<any> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'AnyType'; | ||
@@ -886,2 +979,5 @@ constructor(); | ||
export declare class ObjectType extends Type<object> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ObjectType'; | ||
@@ -941,2 +1037,5 @@ constructor(); | ||
readonly props: P; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'StrictType'; | ||
@@ -943,0 +1042,0 @@ constructor(name: string, is: StrictType<P, A, O, I>['is'], validate: StrictType<P, A, O, I>['validate'], encode: StrictType<P, A, O, I>['encode'], props: P); |
@@ -143,2 +143,5 @@ var __extends = (this && this.__extends) || (function () { | ||
var _this = _super.call(this, 'null', function (u) { return u === null; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'NullType'; | ||
@@ -161,2 +164,5 @@ return _this; | ||
var _this = _super.call(this, 'undefined', function (u) { return u === void 0; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'UndefinedType'; | ||
@@ -176,2 +182,5 @@ return _this; | ||
var _this = _super.call(this, 'void', undefinedType.is, undefinedType.validate, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'VoidType'; | ||
@@ -194,2 +203,5 @@ return _this; | ||
var _this = _super.call(this, 'unknown', function (_) { return true; }, success, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'UnknownType'; | ||
@@ -212,2 +224,5 @@ return _this; | ||
var _this = _super.call(this, 'string', function (u) { return typeof u === 'string'; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'StringType'; | ||
@@ -230,2 +245,5 @@ return _this; | ||
var _this = _super.call(this, 'number', function (u) { return typeof u === 'number'; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'NumberType'; | ||
@@ -250,2 +268,5 @@ return _this; | ||
function (u) { return typeof u === 'bigint'; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'BigIntType'; | ||
@@ -268,2 +289,5 @@ return _this; | ||
var _this = _super.call(this, 'boolean', function (u) { return typeof u === 'boolean'; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'BooleanType'; | ||
@@ -286,2 +310,5 @@ return _this; | ||
var _this = _super.call(this, 'UnknownArray', Array.isArray, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'AnyArrayType'; | ||
@@ -307,2 +334,5 @@ return _this; | ||
}, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'AnyDictionaryType'; | ||
@@ -328,2 +358,5 @@ return _this; | ||
function (u) { return typeof u === 'function'; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'FunctionType'; | ||
@@ -350,2 +383,5 @@ return _this; | ||
_this.predicate = predicate; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'RefinementType'; | ||
@@ -377,2 +413,5 @@ return _this; | ||
_this.value = value; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'LiteralType'; | ||
@@ -400,2 +439,5 @@ return _this; | ||
_this.keys = keys; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'KeyofType'; | ||
@@ -426,2 +468,5 @@ return _this; | ||
_this.runDefinition = runDefinition; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'RecursiveType'; | ||
@@ -463,2 +508,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ArrayType'; | ||
@@ -508,2 +556,5 @@ return _this; | ||
_this.props = props; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'InterfaceType'; | ||
@@ -598,2 +649,5 @@ return _this; | ||
_this.props = props; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'PartialType'; | ||
@@ -678,2 +732,5 @@ return _this; | ||
_this.codomain = codomain; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'DictionaryType'; | ||
@@ -811,2 +868,5 @@ return _this; | ||
_this.types = types; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'UnionType'; | ||
@@ -903,2 +963,5 @@ return _this; | ||
_this.types = types; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'IntersectionType'; | ||
@@ -972,2 +1035,5 @@ return _this; | ||
_this.types = types; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'TupleType'; | ||
@@ -1016,2 +1082,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ReadonlyType'; | ||
@@ -1045,2 +1114,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ReadonlyArrayType'; | ||
@@ -1124,2 +1196,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ExactType'; | ||
@@ -1233,2 +1308,5 @@ return _this; | ||
}) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'NeverType'; | ||
@@ -1254,2 +1332,5 @@ return _this; | ||
var _this = _super.call(this, 'any', function (_) { return true; }, success, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'AnyType'; | ||
@@ -1282,2 +1363,5 @@ return _this; | ||
var _this = _super.call(this, 'object', function (u) { return u !== null && typeof u === 'object'; }, function (u, c) { return (_this.is(u) ? success(u) : failure(u, c)); }, identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ObjectType'; | ||
@@ -1333,2 +1417,5 @@ return _this; | ||
_this.props = props; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'StrictType'; | ||
@@ -1335,0 +1422,0 @@ return _this; |
@@ -104,4 +104,13 @@ /** | ||
readonly encode: Encode<A, O>; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _A: A; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _O: O; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _I: I; | ||
@@ -167,2 +176,5 @@ constructor( | ||
export declare class NullType extends Type<null> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'NullType'; | ||
@@ -184,2 +196,5 @@ constructor(); | ||
export declare class UndefinedType extends Type<undefined> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'UndefinedType'; | ||
@@ -198,2 +213,5 @@ constructor(); | ||
export declare class VoidType extends Type<void> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'VoidType'; | ||
@@ -215,2 +233,5 @@ constructor(); | ||
export declare class UnknownType extends Type<unknown> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'UnknownType'; | ||
@@ -232,2 +253,5 @@ constructor(); | ||
export declare class StringType extends Type<string> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'StringType'; | ||
@@ -249,2 +273,5 @@ constructor(); | ||
export declare class NumberType extends Type<number> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'NumberType'; | ||
@@ -266,2 +293,5 @@ constructor(); | ||
export declare class BigIntType extends Type<bigint> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'BigIntType'; | ||
@@ -283,2 +313,5 @@ constructor(); | ||
export declare class BooleanType extends Type<boolean> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'BooleanType'; | ||
@@ -300,2 +333,5 @@ constructor(); | ||
export declare class AnyArrayType extends Type<Array<unknown>> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'AnyArrayType'; | ||
@@ -319,2 +355,5 @@ constructor(); | ||
}> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'AnyDictionaryType'; | ||
@@ -337,2 +376,5 @@ constructor(); | ||
export declare class FunctionType extends Type<Function> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'FunctionType'; | ||
@@ -358,2 +400,5 @@ constructor(); | ||
readonly predicate: Predicate<A>; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'RefinementType'; | ||
@@ -403,2 +448,5 @@ constructor(name: string, is: RefinementType<C, A, O, I>['is'], validate: RefinementType<C, A, O, I>['validate'], encode: RefinementType<C, A, O, I>['encode'], type: C, predicate: Predicate<A>); | ||
readonly value: V; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'LiteralType'; | ||
@@ -423,2 +471,5 @@ constructor(name: string, is: LiteralType<V>['is'], validate: LiteralType<V>['validate'], encode: LiteralType<V>['encode'], value: V); | ||
readonly keys: D; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'KeyofType'; | ||
@@ -445,4 +496,10 @@ constructor(name: string, is: KeyofType<D>['is'], validate: KeyofType<D>['validate'], encode: KeyofType<D>['encode'], keys: D); | ||
runDefinition: () => C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'RecursiveType'; | ||
constructor(name: string, is: RecursiveType<C, A, O, I>['is'], validate: RecursiveType<C, A, O, I>['validate'], encode: RecursiveType<C, A, O, I>['encode'], runDefinition: () => C); | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly type: C; | ||
@@ -459,2 +516,5 @@ } | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ArrayType'; | ||
@@ -477,2 +537,5 @@ constructor(name: string, is: ArrayType<C, A, O, I>['is'], validate: ArrayType<C, A, O, I>['validate'], encode: ArrayType<C, A, O, I>['encode'], type: C); | ||
readonly props: P; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'InterfaceType'; | ||
@@ -523,2 +586,5 @@ constructor(name: string, is: InterfaceType<P, A, O, I>['is'], validate: InterfaceType<P, A, O, I>['validate'], encode: InterfaceType<P, A, O, I>['encode'], props: P); | ||
readonly props: P; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'PartialType'; | ||
@@ -558,2 +624,5 @@ constructor(name: string, is: PartialType<P, A, O, I>['is'], validate: PartialType<P, A, O, I>['validate'], encode: PartialType<P, A, O, I>['encode'], props: P); | ||
readonly codomain: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'DictionaryType'; | ||
@@ -592,2 +661,5 @@ constructor(name: string, is: DictionaryType<D, C, A, O, I>['is'], validate: DictionaryType<D, C, A, O, I>['validate'], encode: DictionaryType<D, C, A, O, I>['encode'], domain: D, codomain: C); | ||
readonly types: CS; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'UnionType'; | ||
@@ -610,2 +682,5 @@ constructor(name: string, is: UnionType<CS, A, O, I>['is'], validate: UnionType<CS, A, O, I>['validate'], encode: UnionType<CS, A, O, I>['encode'], types: CS); | ||
readonly types: CS; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'IntersectionType'; | ||
@@ -647,2 +722,5 @@ constructor(name: string, is: IntersectionType<CS, A, O, I>['is'], validate: IntersectionType<CS, A, O, I>['validate'], encode: IntersectionType<CS, A, O, I>['encode'], types: CS); | ||
readonly types: CS; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'TupleType'; | ||
@@ -689,2 +767,5 @@ constructor(name: string, is: TupleType<CS, A, O, I>['is'], validate: TupleType<CS, A, O, I>['validate'], encode: TupleType<CS, A, O, I>['encode'], types: CS); | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ReadonlyType'; | ||
@@ -711,2 +792,5 @@ constructor(name: string, is: ReadonlyType<C, A, O, I>['is'], validate: ReadonlyType<C, A, O, I>['validate'], encode: ReadonlyType<C, A, O, I>['encode'], type: C); | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ReadonlyArrayType'; | ||
@@ -756,2 +840,5 @@ constructor(name: string, is: ReadonlyArrayType<C, A, O, I>['is'], validate: ReadonlyArrayType<C, A, O, I>['validate'], encode: ReadonlyArrayType<C, A, O, I>['encode'], type: C); | ||
readonly type: C; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ExactType'; | ||
@@ -839,2 +926,5 @@ constructor(name: string, is: ExactType<C, A, O, I>['is'], validate: ExactType<C, A, O, I>['validate'], encode: ExactType<C, A, O, I>['encode'], type: C); | ||
export declare class NeverType extends Type<never> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'NeverType'; | ||
@@ -859,2 +949,5 @@ constructor(); | ||
export declare class AnyType extends Type<any> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'AnyType'; | ||
@@ -886,2 +979,5 @@ constructor(); | ||
export declare class ObjectType extends Type<object> { | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'ObjectType'; | ||
@@ -941,2 +1037,5 @@ constructor(); | ||
readonly props: P; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
readonly _tag: 'StrictType'; | ||
@@ -943,0 +1042,0 @@ constructor(name: string, is: StrictType<P, A, O, I>['is'], validate: StrictType<P, A, O, I>['validate'], encode: StrictType<P, A, O, I>['encode'], props: P); |
@@ -145,2 +145,5 @@ "use strict"; | ||
var _this = _super.call(this, 'null', function (u) { return u === null; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'NullType'; | ||
@@ -164,2 +167,5 @@ return _this; | ||
var _this = _super.call(this, 'undefined', function (u) { return u === void 0; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'UndefinedType'; | ||
@@ -180,2 +186,5 @@ return _this; | ||
var _this = _super.call(this, 'void', undefinedType.is, undefinedType.validate, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'VoidType'; | ||
@@ -199,2 +208,5 @@ return _this; | ||
var _this = _super.call(this, 'unknown', function (_) { return true; }, exports.success, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'UnknownType'; | ||
@@ -217,2 +229,5 @@ return _this; | ||
var _this = _super.call(this, 'string', function (u) { return typeof u === 'string'; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'StringType'; | ||
@@ -235,2 +250,5 @@ return _this; | ||
var _this = _super.call(this, 'number', function (u) { return typeof u === 'number'; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'NumberType'; | ||
@@ -255,2 +273,5 @@ return _this; | ||
function (u) { return typeof u === 'bigint'; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'BigIntType'; | ||
@@ -273,2 +294,5 @@ return _this; | ||
var _this = _super.call(this, 'boolean', function (u) { return typeof u === 'boolean'; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'BooleanType'; | ||
@@ -291,2 +315,5 @@ return _this; | ||
var _this = _super.call(this, 'UnknownArray', Array.isArray, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'AnyArrayType'; | ||
@@ -313,2 +340,5 @@ return _this; | ||
}, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'AnyDictionaryType'; | ||
@@ -334,2 +364,5 @@ return _this; | ||
function (u) { return typeof u === 'function'; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'FunctionType'; | ||
@@ -356,2 +389,5 @@ return _this; | ||
_this.predicate = predicate; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'RefinementType'; | ||
@@ -383,2 +419,5 @@ return _this; | ||
_this.value = value; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'LiteralType'; | ||
@@ -406,2 +445,5 @@ return _this; | ||
_this.keys = keys; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'KeyofType'; | ||
@@ -432,2 +474,5 @@ return _this; | ||
_this.runDefinition = runDefinition; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'RecursiveType'; | ||
@@ -469,2 +514,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ArrayType'; | ||
@@ -514,2 +562,5 @@ return _this; | ||
_this.props = props; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'InterfaceType'; | ||
@@ -605,2 +656,5 @@ return _this; | ||
_this.props = props; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'PartialType'; | ||
@@ -685,2 +739,5 @@ return _this; | ||
_this.codomain = codomain; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'DictionaryType'; | ||
@@ -820,2 +877,5 @@ return _this; | ||
_this.types = types; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'UnionType'; | ||
@@ -912,2 +972,5 @@ return _this; | ||
_this.types = types; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'IntersectionType'; | ||
@@ -982,2 +1045,5 @@ return _this; | ||
_this.types = types; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'TupleType'; | ||
@@ -1027,2 +1093,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ReadonlyType'; | ||
@@ -1056,2 +1125,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ReadonlyArrayType'; | ||
@@ -1135,2 +1207,5 @@ return _this; | ||
_this.type = type; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ExactType'; | ||
@@ -1215,2 +1290,5 @@ return _this; | ||
}) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'NeverType'; | ||
@@ -1236,2 +1314,5 @@ return _this; | ||
var _this = _super.call(this, 'any', function (_) { return true; }, exports.success, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'AnyType'; | ||
@@ -1264,2 +1345,5 @@ return _this; | ||
var _this = _super.call(this, 'object', function (u) { return u !== null && typeof u === 'object'; }, function (u, c) { return (_this.is(u) ? exports.success(u) : exports.failure(u, c)); }, exports.identity) || this; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'ObjectType'; | ||
@@ -1316,2 +1400,5 @@ return _this; | ||
_this.props = props; | ||
/** | ||
* @since 1.0.0 | ||
*/ | ||
_this._tag = 'StrictType'; | ||
@@ -1318,0 +1405,0 @@ return _this; |
{ | ||
"name": "io-ts", | ||
"version": "2.1.3", | ||
"version": "2.2.0", | ||
"description": "TypeScript compatible runtime type system for IO validation", | ||
@@ -26,3 +26,3 @@ "files": [ | ||
"mocha": "TS_NODE_CACHE=false mocha -r ts-node/register test/*.ts", | ||
"doctoc": "doctoc README.md", | ||
"doctoc": "doctoc README.md Type.md Decoder.md Encoder.md Codec.md", | ||
"docs": "docs-ts", | ||
@@ -47,19 +47,19 @@ "import-path-rewrite": "import-path-rewrite" | ||
"@types/benchmark": "1.0.31", | ||
"@types/jest": "^23.3.8", | ||
"@types/node": "7.0.4", | ||
"@types/jest": "25.2.1", | ||
"@types/node": "13.11.0", | ||
"benchmark": "2.1.4", | ||
"docs-ts": "^0.3.4", | ||
"doctoc": "^1.4.0", | ||
"docs-ts": "0.4.0", | ||
"doctoc": "1.4.0", | ||
"dtslint": "github:gcanti/dtslint", | ||
"fp-ts": "^2.0.0", | ||
"fp-ts": "2.5.3", | ||
"import-path-rewrite": "github:gcanti/import-path-rewrite", | ||
"jest": "^24.8.0", | ||
"mocha": "^5.2.0", | ||
"prettier": "^1.19.1", | ||
"rimraf": "2.6.2", | ||
"ts-jest": "^24.0.2", | ||
"ts-node": "^7.0.1", | ||
"tslint": "^5.11.0", | ||
"tslint-config-standard": "^8.0.1", | ||
"typescript": "^3.7.4" | ||
"jest": "25.2.7", | ||
"mocha": "7.1.1", | ||
"prettier": "2.0.2", | ||
"rimraf": "3.0.2", | ||
"ts-jest": "25.3.1", | ||
"ts-node": "8.8.2", | ||
"tslint": "6.1.1", | ||
"tslint-config-standard": "9.0.0", | ||
"typescript": "3.8.3" | ||
}, | ||
@@ -66,0 +66,0 @@ "tags": [ |
572
README.md
@@ -6,4 +6,2 @@ [![build status](https://img.shields.io/travis/gcanti/io-ts/master.svg?style=flat-square)](https://travis-ci.org/gcanti/io-ts) | ||
Table of contents | ||
<!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
@@ -13,19 +11,3 @@ <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
- [Installation](#installation) | ||
- [The idea](#the-idea) | ||
- [TypeScript integration](#typescript-integration) | ||
- [TypeScript compatibility](#typescript-compatibility) | ||
- [Error reporters](#error-reporters) | ||
- [Custom error messages](#custom-error-messages) | ||
- [Implemented types / combinators](#implemented-types--combinators) | ||
- [Recursive types](#recursive-types) | ||
- [Mutually recursive types](#mutually-recursive-types) | ||
- [Branded types / Refinements](#branded-types--refinements) | ||
- [Exact types](#exact-types) | ||
- [Mixing required and optional props](#mixing-required-and-optional-props) | ||
- [Custom types](#custom-types) | ||
- [Generic Types](#generic-types) | ||
- [Piping](#piping) | ||
- [Community](#community) | ||
- [Tips and Tricks](#tips-and-tricks) | ||
- [Union of string literals](#union-of-string-literals) | ||
- [Documentation](#documentation) | ||
@@ -44,549 +26,17 @@ <!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
# The idea | ||
# Documentation | ||
A value of type `Type<A, O, I>` (called "codec") is the runtime representation of the static type `A`. | ||
- [API Reference](https://gcanti.github.io/io-ts/modules/) | ||
A codec can: | ||
## Usage | ||
- decode inputs of type `I` (through `decode`) | ||
- encode outputs of type `O` (through `encode`) | ||
- be used as a custom [type guard](https://basarat.gitbooks.io/typescript/content/docs/types/typeGuard.html) (through `is`) | ||
**Experimental features** (version `2.2+`) | ||
```ts | ||
class Type<A, O, I> { | ||
constructor( | ||
/** a unique name for this codec */ | ||
readonly name: string, | ||
- [`Decoder`](Decoder.md) | ||
- [`Encoder`](Encoder.md) | ||
- [`Codec`](Codec.md) | ||
- [`Schema` (advanced feature)](Schema.md) | ||
/** a custom type guard */ | ||
readonly is: (u: unknown) => u is A, | ||
**Stable** (old) | ||
/** succeeds if a value of type I can be decoded to a value of type A */ | ||
readonly validate: (input: I, context: Context) => Either<Errors, A>, | ||
/** converts a value of type A to a value of type O */ | ||
readonly encode: (a: A) => O | ||
) {} | ||
/** a version of `validate` with a default context */ | ||
decode(i: I): Either<Errors, A> | ||
} | ||
``` | ||
The [`Either`](https://gcanti.github.io/fp-ts/modules/Either.ts.html) type returned by `decode` is defined in [fp-ts](https://github.com/gcanti/fp-ts), a library containing implementations of common algebraic types in TypeScript. | ||
The `Either` type represents a value of one of two possible types (a disjoint union). An instance of `Either` is either an instance of `Left` or `Right`: | ||
```ts | ||
type Either<E, A> = | ||
| { | ||
readonly _tag: 'Left' | ||
readonly left: E | ||
} | ||
| { | ||
readonly _tag: 'Right' | ||
readonly right: A | ||
} | ||
``` | ||
Convention dictates that `Left` is used for **failure** and `Right` is used for **success**. | ||
**Example** | ||
A codec representing `string` can be defined as: | ||
```ts | ||
import * as t from 'io-ts' | ||
const string = new t.Type<string, string, unknown>( | ||
'string', | ||
(input: unknown): input is string => typeof input === 'string', | ||
// `t.success` and `t.failure` are helpers used to build `Either` instances | ||
(input, context) => (typeof input === 'string' ? t.success(input) : t.failure(input, context)), | ||
// `A` and `O` are the same, so `encode` is just the identity function | ||
t.identity | ||
) | ||
``` | ||
and we can use it as follows: | ||
```ts | ||
import { isRight } from 'fp-ts/lib/Either' | ||
isRight(string.decode('a string')) // true | ||
isRight(string.decode(null)) // false | ||
``` | ||
More generally the result of calling `decode` can be handled using [`fold`](https://gcanti.github.io/fp-ts/modules/Either.ts.html#fold-function) along with `pipe` (which is similar to the pipeline operator) | ||
```ts | ||
import * as t from 'io-ts' | ||
import { pipe } from 'fp-ts/lib/pipeable' | ||
import { fold } from 'fp-ts/lib/Either' | ||
// failure handler | ||
const onLeft = (errors: t.Errors): string => `${errors.length} error(s) found` | ||
// success handler | ||
const onRight = (s: string) => `No errors: ${s}` | ||
pipe(t.string.decode('a string'), fold(onLeft, onRight)) | ||
// => "No errors: a string" | ||
pipe(t.string.decode(null), fold(onLeft, onRight)) | ||
// => "1 error(s) found" | ||
``` | ||
We can combine these codecs through [combinators](#implemented-types--combinators) to build composite types which represent entities like domain models, request payloads etc. in our applications: | ||
```ts | ||
import * as t from 'io-ts' | ||
const User = t.type({ | ||
userId: t.number, | ||
name: t.string | ||
}) | ||
``` | ||
So this is equivalent to defining something like: | ||
```ts | ||
type User = { | ||
userId: number | ||
name: string | ||
} | ||
``` | ||
The advantage of using `io-ts` to define the runtime type is that we can validate the type at runtime, and we can also extract the corresponding static type, so we don’t have to define it twice. | ||
# TypeScript integration | ||
Codecs can be inspected: | ||
![instrospection](images/introspection.png) | ||
This library uses TypeScript extensively. Its API is defined in a way which automatically infers types for produced | ||
values | ||
![inference](images/inference.png) | ||
Note that the type annotation isn't needed, TypeScript infers the type automatically based on a schema (and comments are preserved). | ||
Static types can be extracted from codecs using the `TypeOf` operator: | ||
```ts | ||
type User = t.TypeOf<typeof User> | ||
// same as | ||
type User = { | ||
userId: number | ||
name: string | ||
} | ||
``` | ||
# TypeScript compatibility | ||
The stable version is tested against TypeScript 3.5.2 | ||
| io-ts version | required TypeScript version | | ||
| ------------- | --------------------------- | | ||
| 2.x+ | 3.5.2+ | | ||
| 1.6.x+ | 3.2.2+ | | ||
| 1.5.3 | 3.0.1+ | | ||
| 1.5.2- | 2.7.2+ | | ||
**Note**. This library is conceived, tested and is supposed to be consumed by TypeScript with the `strict` flag turned on. | ||
**Note**. If you are running `< typescript@3.0.1` you have to polyfill `unknown`. | ||
You can use [unknown-ts](https://github.com/gcanti/unknown-ts) as a polyfill. | ||
# Error reporters | ||
A reporter implements the following interface | ||
```ts | ||
interface Reporter<A> { | ||
report: (validation: Validation<any>) => A | ||
} | ||
``` | ||
This package exports a default `PathReporter` reporter | ||
Example | ||
```ts | ||
import { PathReporter } from 'io-ts/lib/PathReporter' | ||
const result = User.decode({ name: 'Giulio' }) | ||
console.log(PathReporter.report(result)) | ||
// => [ 'Invalid value undefined supplied to : { userId: number, name: string }/userId: number' ] | ||
``` | ||
You can define your own reporter. `Errors` has the following type | ||
```ts | ||
interface ContextEntry { | ||
readonly key: string | ||
readonly type: Decoder<any, any> | ||
} | ||
interface Context extends ReadonlyArray<ContextEntry> {} | ||
interface ValidationError { | ||
readonly value: unknown | ||
readonly context: Context | ||
} | ||
interface Errors extends Array<ValidationError> {} | ||
``` | ||
Example | ||
```ts | ||
import { pipe } from 'fp-ts/lib/pipeable' | ||
import { fold } from 'fp-ts/lib/Either' | ||
const getPaths = <A>(v: t.Validation<A>): Array<string> => { | ||
return pipe( | ||
v, | ||
fold( | ||
errors => errors.map(error => error.context.map(({ key }) => key).join('.')), | ||
() => ['no errors'] | ||
) | ||
) | ||
} | ||
console.log(getPaths(User.decode({}))) // => [ '.userId', '.name' ] | ||
``` | ||
# Custom error messages | ||
You can set your own error message by providing a `message` argument to `failure` | ||
Example | ||
```ts | ||
import { either } from 'fp-ts/lib/Either' | ||
const NumberFromString = new t.Type<number, string, unknown>( | ||
'NumberFromString', | ||
t.number.is, | ||
(u, c) => | ||
either.chain(t.string.validate(u, c), s => { | ||
const n = +s | ||
return isNaN(n) ? t.failure(u, c, 'cannot parse to a number') : t.success(n) | ||
}), | ||
String | ||
) | ||
console.log(PathReporter.report(NumberFromString.decode('a'))) | ||
// => ['cannot parse to a number'] | ||
``` | ||
You can also use the [`withMessage`](https://gcanti.github.io/io-ts-types/modules/withMessage.ts.html) helper from [io-ts-types](https://github.com/gcanti/io-ts-types) | ||
# Implemented types / combinators | ||
| Type | TypeScript | codec / combinator | | ||
| --------------------------- | --------------------------- | -------------------------------------------------------------------- | | ||
| null | `null` | `t.null` or `t.nullType` | | ||
| undefined | `undefined` | `t.undefined` | | ||
| void | `void` | `t.void` or `t.voidType` | | ||
| string | `string` | `t.string` | | ||
| number | `number` | `t.number` | | ||
| boolean | `boolean` | `t.boolean` | | ||
| unknown | `unknown` | `t.unknown` | | ||
| array of unknown | `Array<unknown>` | `t.UnknownArray` | | ||
| array of type | `Array<A>` | `t.array(A)` | | ||
| record of unknown | `Record<string, unknown>` | `t.UnknownRecord` | | ||
| record of type | `Record<K, A>` | `t.record(K, A)` | | ||
| function | `Function` | `t.Function` | | ||
| literal | `'s'` | `t.literal('s')` | | ||
| partial | `Partial<{ name: string }>` | `t.partial({ name: t.string })` | | ||
| readonly | `Readonly<A>` | `t.readonly(A)` | | ||
| readonly array | `ReadonlyArray<A>` | `t.readonlyArray(A)` | | ||
| type alias | `type T = { name: A }` | `t.type({ name: A })` | | ||
| tuple | `[ A, B ]` | `t.tuple([ A, B ])` | | ||
| union | `A \| B` | `t.union([ A, B ])` | | ||
| intersection | `A & B` | `t.intersection([ A, B ])` | | ||
| keyof | `keyof M` | `t.keyof(M)` (**only supports string keys**) | | ||
| recursive types | | `t.recursion(name, definition)` | | ||
| branded types / refinements | ✘ | `t.brand(A, predicate, brand)` | | ||
| integer | ✘ | `t.Int` (built-in branded codec) | | ||
| exact types | ✘ | `t.exact(type)` | | ||
| strict | ✘ | `t.strict({ name: A })` (an alias of `t.exact(t.type({ name: A })))` | | ||
# Recursive types | ||
Recursive types can't be inferred by TypeScript so you must provide the static type as a hint | ||
```ts | ||
interface Category { | ||
name: string | ||
categories: Array<Category> | ||
} | ||
const Category: t.Type<Category> = t.recursion('Category', () => | ||
t.type({ | ||
name: t.string, | ||
categories: t.array(Category) | ||
}) | ||
) | ||
``` | ||
## Mutually recursive types | ||
```ts | ||
interface Foo { | ||
type: 'Foo' | ||
b: Bar | undefined | ||
} | ||
interface Bar { | ||
type: 'Bar' | ||
a: Foo | undefined | ||
} | ||
const Foo: t.Type<Foo> = t.recursion('Foo', () => | ||
t.type({ | ||
type: t.literal('Foo'), | ||
b: t.union([Bar, t.undefined]) | ||
}) | ||
) | ||
const Bar: t.Type<Bar> = t.recursion('Bar', () => | ||
t.type({ | ||
type: t.literal('Bar'), | ||
a: t.union([Foo, t.undefined]) | ||
}) | ||
) | ||
``` | ||
# Branded types / Refinements | ||
You can brand / refine a codec (_any_ codec) using the `brand` combinator | ||
```ts | ||
// a unique brand for positive numbers | ||
interface PositiveBrand { | ||
readonly Positive: unique symbol // use `unique symbol` here to ensure uniqueness across modules / packages | ||
} | ||
const Positive = t.brand( | ||
t.number, // a codec representing the type to be refined | ||
(n): n is t.Branded<number, PositiveBrand> => n >= 0, // a custom type guard using the build-in helper `Branded` | ||
'Positive' // the name must match the readonly field in the brand | ||
) | ||
type Positive = t.TypeOf<typeof Positive> | ||
/* | ||
same as | ||
type Positive = number & t.Brand<PositiveBrand> | ||
*/ | ||
``` | ||
Branded codecs can be merged with `t.intersection` | ||
```ts | ||
// t.Int is a built-in branded codec | ||
const PositiveInt = t.intersection([t.Int, Positive]) | ||
type PositiveInt = t.TypeOf<typeof PositiveInt> | ||
/* | ||
same as | ||
type PositiveInt = number & t.Brand<t.IntBrand> & t.Brand<PositiveBrand> | ||
*/ | ||
``` | ||
# Exact types | ||
You can make a codec exact (which means that additional properties are stripped) using the `exact` combinator | ||
```ts | ||
const ExactUser = t.exact(User) | ||
User.decode({ userId: 1, name: 'Giulio', age: 45 }) // ok, result is right({ userId: 1, name: 'Giulio', age: 45 }) | ||
ExactUser.decode({ userId: 1, name: 'Giulio', age: 43 }) // ok but result is right({ userId: 1, name: 'Giulio' }) | ||
``` | ||
# Mixing required and optional props | ||
You can mix required and optional props using an intersection | ||
```ts | ||
const A = t.type({ | ||
foo: t.string | ||
}) | ||
const B = t.partial({ | ||
bar: t.number | ||
}) | ||
const C = t.intersection([A, B]) | ||
type C = t.TypeOf<typeof C> | ||
// same as | ||
type C = { | ||
foo: string | ||
} & { | ||
bar?: number | undefined | ||
} | ||
``` | ||
You can apply `partial` to an already defined codec via its `props` field | ||
```ts | ||
const PartialUser = t.partial(User.props) | ||
type PartialUser = t.TypeOf<typeof PartialUser> | ||
// same as | ||
type PartialUser = { | ||
name?: string | ||
age?: number | ||
} | ||
``` | ||
# Custom types | ||
You can define your own types. Let's see an example | ||
```ts | ||
import { either } from 'fp-ts/lib/Either' | ||
// represents a Date from an ISO string | ||
const DateFromString = new t.Type<Date, string, unknown>( | ||
'DateFromString', | ||
(u): u is Date => u instanceof Date, | ||
(u, c) => | ||
either.chain(t.string.validate(u, c), s => { | ||
const d = new Date(s) | ||
return isNaN(d.getTime()) ? t.failure(u, c) : t.success(d) | ||
}), | ||
a => a.toISOString() | ||
) | ||
const s = new Date(1973, 10, 30).toISOString() | ||
DateFromString.decode(s) | ||
// right(new Date('1973-11-29T23:00:00.000Z')) | ||
DateFromString.decode('foo') | ||
// left(errors...) | ||
``` | ||
Note that you can **deserialize** while validating. | ||
# Generic Types | ||
Polymorphic codecs are represented using functions. | ||
For example, the following typescript: | ||
```ts | ||
interface ResponseBody<T> { | ||
result: T | ||
_links: Links | ||
} | ||
interface Links { | ||
previous: string | ||
next: string | ||
} | ||
``` | ||
Would be: | ||
```ts | ||
// where `t.Mixed = t.Type<any, any, unknown>` | ||
const responseBody = <C extends t.Mixed>(codec: C) => | ||
t.type({ | ||
result: codec, | ||
_links: Links | ||
}) | ||
const Links = t.type({ | ||
previous: t.string, | ||
next: t.string | ||
}) | ||
``` | ||
And used like: | ||
```ts | ||
const UserModel = t.type({ | ||
name: t.string | ||
}) | ||
functionThatRequiresRuntimeType(responseBody(t.array(UserModel)), ...params) | ||
``` | ||
# Piping | ||
You can pipe two codecs if their type parameters do align | ||
```ts | ||
const NumberCodec = new t.Type<number, string, string>( | ||
'NumberCodec', | ||
t.number.is, | ||
(s, c) => { | ||
const n = parseFloat(s) | ||
return isNaN(n) ? t.failure(s, c) : t.success(n) | ||
}, | ||
String | ||
) | ||
const NumberFromString = t.string.pipe(NumberCodec, 'NumberFromString') | ||
``` | ||
# Community | ||
- `io-ts@2.x` | ||
- [io-ts-types](https://github.com/gcanti/io-ts-types) - A collection of codecs and combinators for use with | ||
io-ts | ||
- [io-ts-reporters](https://github.com/OliverJAsh/io-ts-reporters) - Error reporters for io-ts | ||
- [io-ts-promise](https://github.com/aeirola/io-ts-promise) - Convenience library for using io-ts with promise-based APIs | ||
- `io-ts@1.x` | ||
- [geojson-iots](https://github.com/pierremarc/geojson-iots) - codecs for GeoJSON as defined in rfc7946 made with | ||
io-ts | ||
- [graphql-to-io-ts](https://github.com/micimize/graphql-to-io-ts) - Generate typescript and corresponding io-ts types from a graphql schema | ||
# Tips and Tricks | ||
## Union of string literals | ||
Use `keyof` instead of `union` when defining a union of string literals | ||
```ts | ||
const Bad = t.union([ | ||
t.literal('foo'), | ||
t.literal('bar'), | ||
t.literal('baz') | ||
// etc... | ||
]) | ||
const Good = t.keyof({ | ||
foo: null, | ||
bar: null, | ||
baz: null | ||
// etc... | ||
}) | ||
``` | ||
Benefits | ||
- unique check for free | ||
- better performance, `O(log(n))` vs `O(n)` | ||
Beware that `keyof` is designed to work with objects containing string keys. If you intend to define a numbers enumeration, you have to use an `union` of number literals : | ||
```ts | ||
const HttpCode = t.union([ | ||
t.literal(200), | ||
t.literal(201), | ||
t.literal(202) | ||
// etc... | ||
]) | ||
``` | ||
- [`Type`](Type.md) |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
257275
48
8710
40
6