Comparing version 0.2.0 to 0.2.1
@@ -15,7 +15,8 @@ # Changelog | ||
# 0.2.0 | ||
# 0.2.1 | ||
- **New Feature** | ||
- add `partial` combinator | ||
- add `readonly` combinator | ||
- add `partial` combinator (makes optional props possible) | ||
- add `readonly` combinator (values are not frozen in production) | ||
- add `readonlyArray` combinator (values are not frozen in production) | ||
- add `never` type | ||
@@ -32,3 +33,3 @@ - **Breaking Changes** | ||
- **Bug Fix** | ||
- revert pruning excess properties | ||
- revert pruning excess properties (see https://github.com/gcanti/io-ts/pull/27 for context) | ||
- revert `intersection` combinator accepting only `InterfaceType`s | ||
@@ -35,0 +36,0 @@ |
@@ -193,2 +193,7 @@ import { Either } from 'fp-ts/lib/Either'; | ||
export declare function readonly<RT extends Any>(type: RT, name?: string): ReadonlyType<RT>; | ||
export declare class ReadonlyArrayType<RT extends Any> extends Type<ReadonlyArray<TypeOf<RT>>> { | ||
readonly type: RT; | ||
constructor(name: string, validate: Validate<ReadonlyArray<TypeOf<RT>>>, type: RT); | ||
} | ||
export declare function readonlyArray<RT extends Any>(type: RT, name?: string): ReadonlyArrayType<RT>; | ||
export { nullType as null, undefinedType as undefined, arrayType as Array, functionType as Function, interfaceType as interface }; |
@@ -333,2 +333,5 @@ var __extends = (this && this.__extends) || (function () { | ||
} | ||
// | ||
// readonly | ||
// | ||
var ReadonlyType = (function (_super) { | ||
@@ -352,3 +355,25 @@ __extends(ReadonlyType, _super); | ||
} | ||
// | ||
// readonlyArray | ||
// | ||
var ReadonlyArrayType = (function (_super) { | ||
__extends(ReadonlyArrayType, _super); | ||
function ReadonlyArrayType(name, validate, type) { | ||
var _this = _super.call(this, name, validate) || this; | ||
_this.type = type; | ||
return _this; | ||
} | ||
return ReadonlyArrayType; | ||
}(Type)); | ||
export { ReadonlyArrayType }; | ||
export function readonlyArray(type, name) { | ||
var arrayType = array(type); | ||
return new ReadonlyArrayType(name || "ReadonlyArray<" + getTypeName(type) + ">", function (v, c) { return arrayType.validate(v, c).map(function (x) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
return Object.freeze(x); | ||
} | ||
return x; | ||
}); }, type); | ||
} | ||
export { nullType as null, undefinedType as undefined, arrayType as Array, functionType as Function, interfaceType as interface }; | ||
//# sourceMappingURL=index.js.map |
@@ -193,2 +193,7 @@ import { Either } from 'fp-ts/lib/Either'; | ||
export declare function readonly<RT extends Any>(type: RT, name?: string): ReadonlyType<RT>; | ||
export declare class ReadonlyArrayType<RT extends Any> extends Type<ReadonlyArray<TypeOf<RT>>> { | ||
readonly type: RT; | ||
constructor(name: string, validate: Validate<ReadonlyArray<TypeOf<RT>>>, type: RT); | ||
} | ||
export declare function readonlyArray<RT extends Any>(type: RT, name?: string): ReadonlyArrayType<RT>; | ||
export { nullType as null, undefinedType as undefined, arrayType as Array, functionType as Function, interfaceType as interface }; |
@@ -354,2 +354,5 @@ "use strict"; | ||
exports.tuple = tuple; | ||
// | ||
// readonly | ||
// | ||
var ReadonlyType = (function (_super) { | ||
@@ -374,2 +377,25 @@ __extends(ReadonlyType, _super); | ||
exports.readonly = readonly; | ||
// | ||
// readonlyArray | ||
// | ||
var ReadonlyArrayType = (function (_super) { | ||
__extends(ReadonlyArrayType, _super); | ||
function ReadonlyArrayType(name, validate, type) { | ||
var _this = _super.call(this, name, validate) || this; | ||
_this.type = type; | ||
return _this; | ||
} | ||
return ReadonlyArrayType; | ||
}(Type)); | ||
exports.ReadonlyArrayType = ReadonlyArrayType; | ||
function readonlyArray(type, name) { | ||
var arrayType = array(type); | ||
return new ReadonlyArrayType(name || "ReadonlyArray<" + getTypeName(type) + ">", function (v, c) { return arrayType.validate(v, c).map(function (x) { | ||
if (process.env.NODE_ENV !== 'production') { | ||
return Object.freeze(x); | ||
} | ||
return x; | ||
}); }, type); | ||
} | ||
exports.readonlyArray = readonlyArray; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "io-ts", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "TypeScript compatible runtime type system for IO validation", | ||
@@ -5,0 +5,0 @@ "files": [ |
@@ -18,2 +18,4 @@ # The idea | ||
Note. The `Either` type is defined in [fp-ts](https://github.com/gcanti/fp-ts), a library containing implementations of common algebraic types in TypeScript. | ||
**Example** | ||
@@ -24,3 +26,2 @@ | ||
```js | ||
import { Right, Left } from 'fp-ts/lib/Either' | ||
import * as t from 'io-ts' | ||
@@ -30,3 +31,3 @@ | ||
'string', | ||
(value, context) => typeof value === 'string' ? new Right(value) : new Left([{ value, context }]) | ||
(value, context) => typeof value === 'string' ? t.success(v) : t.failure<string>(v, c) | ||
) | ||
@@ -137,3 +138,2 @@ ``` | ||
| function | `Function` | `t.Function` | | ||
| instance of `C` | `C` | `t.instanceOf(C)` | | ||
| arrays | `Array<A>` | `t.array(A)` | | ||
@@ -144,2 +144,3 @@ | literal | `'s'` | `t.literal('s')` | | ||
| readonly | `Readonly<{ name: string }>` | `t.readonly({ name: t.string })` | | ||
| readonly array | `ReadonlyArray<number>` | `t.readonlyArray(t.number)` | | ||
| dictionaries | `{ [key: A]: B }` | `t.dictionary(A, B)` | | ||
@@ -154,5 +155,29 @@ | refinement | ✘ | `t.refinement(A, predicate)` | | ||
# Mixing required and optional props | ||
Note. You can mix required and optional props using an intersection | ||
```ts | ||
const A = t.interface({ | ||
foo: t.string | ||
}) | ||
const B = t.partial({ | ||
bar: t.number | ||
}) | ||
const C = t.intersection([A, B]) | ||
type CT = t.TypeOf<typeof C> | ||
// same as | ||
type CT = { | ||
foo: string, | ||
bar?: number | ||
} | ||
``` | ||
# Custom types | ||
You can define your own types. Let's see some examples | ||
You can define your own types. Let's see an example | ||
@@ -193,6 +218,49 @@ ```ts | ||
The problem | ||
```ts | ||
const payload = { | ||
celsius: 100, | ||
fahrenheit: 100 | ||
} | ||
const Payload = t.interface({ | ||
celsius: t.number, | ||
fahrenheit: t.number | ||
}) | ||
// x can be anything | ||
function naiveConvertFtoC(x: number): number { | ||
return (x - 32) / 1.8; | ||
} | ||
// typo: celsius instead of fahrenheit | ||
console.log(t.validate(payload, Payload).map(x => naiveConvertFtoC(x.celsius))) // NO error :( | ||
``` | ||
Solution (branded types) | ||
```ts | ||
export function brand<T, B extends string>(type: t.Type<T>, brand: B): t.Type<T & { readonly __brand: B }> { | ||
return type as any | ||
} | ||
const Fahrenheit = brand(t.number, 'Fahrenheit') | ||
const Celsius = brand(t.number, 'Celsius') | ||
type CelsiusT = t.TypeOf<typeof Celsius> | ||
type FahrenheitT = t.TypeOf<typeof Fahrenheit> | ||
const Payload2 = t.interface({ | ||
celsius: Celsius, | ||
fahrenheit: Fahrenheit | ||
}) | ||
// narrowed types | ||
function convertFtoC(fahrenheit: FahrenheitT): CelsiusT { | ||
return (fahrenheit - 32) / 1.8 as CelsiusT; | ||
} | ||
console.log(t.validate(payload, Payload2).map(x => convertFtoC(x.celsius))) // error: Type '"Celsius"' is not assignable to type '"Fahrenheit"' | ||
console.log(t.validate(payload, Payload2).map(x => convertFtoC(x.fahrenheit))) // ok | ||
``` | ||
@@ -199,0 +267,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
165384
1419
291
4