├── dtslint ├── ts3.5 │ ├── index.d.ts │ ├── tsconfig.json │ ├── tslint.json │ └── index.ts └── index.d.ts ├── docs ├── index.md ├── modules │ ├── index.md │ ├── index.ts.md │ ├── fromRefinement.ts.md │ ├── date.ts.md │ ├── clone.ts.md │ ├── setFromArray.ts.md │ ├── nonEmptyArray.ts.md │ ├── optionFromNullable.ts.md │ ├── NumberFromString.ts.md │ ├── regexp.ts.md │ ├── withFallback.ts.md │ ├── readonlySetFromArray.ts.md │ ├── mapFromEntries.ts.md │ ├── DateFromNumber.ts.md │ ├── withMessage.ts.md │ ├── DateFromUnixTime.ts.md │ ├── DateFromISOString.ts.md │ ├── withValidate.ts.md │ ├── readonlyMapFromEntries.ts.md │ ├── withEncode.ts.md │ ├── fromNullable.ts.md │ ├── IntFromString.ts.md │ ├── fromNewtype.ts.md │ ├── BooleanFromString.ts.md │ ├── readonlyNonEmptyArray.ts.md │ ├── mapOutput.ts.md │ ├── UUID.ts.md │ ├── BooleanFromNumber.ts.md │ ├── getLenses.ts.md │ ├── BigIntFromString.ts.md │ ├── JsonFromString.ts.md │ ├── NonEmptyString.ts.md │ ├── option.ts.md │ └── either.ts.md └── _config.yml ├── .gitignore ├── .vscode └── settings.json ├── .prettierrc ├── tsconfig.build.json ├── tsconfig.tslint.json ├── tsconfig.build-es6.json ├── .github ├── ISSUE_TEMPLATE │ ├── Documentation.md │ ├── Bug_report.md │ └── Feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── main.yml ├── scripts ├── pre-publish.ts ├── run.ts ├── release.ts ├── FileSystem.ts └── build.ts ├── tslint.json ├── test ├── date.ts ├── withMessage.ts ├── UUID.ts ├── BooleanFromString.ts ├── BooleanFromNumber.ts ├── mapOutput.ts ├── regexp.ts ├── tsconfig.json ├── fromNullable.ts ├── getLenses.ts ├── readonlyNonEmptyArray.ts ├── NumberFromString.ts ├── DateFromISOString.ts ├── IntFromString.ts ├── withEncode.ts ├── DateFromNumber.ts ├── readonlySetFromArray.ts ├── fromNewtype.ts ├── NonEmptyString.ts ├── DateFromUnixTime.ts ├── withFallback.ts ├── either.ts ├── readonlyMapFromEntries.ts ├── BigIntFromString.ts ├── nonEmptyArray.ts ├── helpers.ts ├── optionFromNullable.ts ├── setFromArray.ts ├── JsonFromString.ts ├── option.ts └── mapFromEntries.ts ├── src ├── fromRefinement.ts ├── date.ts ├── clone.ts ├── readonlySetFromArray.ts ├── readonlyNonEmptyArray.ts ├── readonlyMapFromEntries.ts ├── regexp.ts ├── withFallback.ts ├── NumberFromString.ts ├── withEncode.ts ├── UUID.ts ├── optionFromNullable.ts ├── DateFromNumber.ts ├── DateFromISOString.ts ├── DateFromUnixTime.ts ├── fromNullable.ts ├── withValidate.ts ├── withMessage.ts ├── NonEmptyString.ts ├── mapOutput.ts ├── nonEmptyArray.ts ├── setFromArray.ts ├── BooleanFromNumber.ts ├── IntFromString.ts ├── BooleanFromString.ts ├── JsonFromString.ts ├── getLenses.ts ├── fromNewtype.ts ├── BigIntFromString.ts ├── option.ts ├── mapFromEntries.ts ├── either.ts └── index.ts ├── jest.config.js ├── tsconfig.json ├── README.md ├── LICENSE ├── package.json └── CHANGELOG.md /dtslint/ts3.5/index.d.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dtslint/index.d.ts: -------------------------------------------------------------------------------- 1 | // TypeScript Version: 3.5 2 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Home 3 | nav_order: 1 4 | --- 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | node_modules 3 | /dist 4 | dev 5 | coverage 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "./node_modules/typescript/lib" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "printWidth": 120 5 | } 6 | -------------------------------------------------------------------------------- /docs/modules/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Modules 3 | has_children: true 4 | permalink: /docs/modules 5 | nav_order: 2 6 | --- 7 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": false 5 | }, 6 | "include": ["./src"] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true 5 | }, 6 | "include": ["./test/**/*"] 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig.build-es6.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.build.json", 3 | "compilerOptions": { 4 | "outDir": "./dist/es6", 5 | "module": "es6" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Documentation" 3 | about: Improvements or suggestions of io-ts-types documentation 4 | --- 5 | 6 | ## 📖 Documentation 7 | -------------------------------------------------------------------------------- /scripts/pre-publish.ts: -------------------------------------------------------------------------------- 1 | import { left } from 'fp-ts/TaskEither' 2 | import { run } from './run' 3 | 4 | const main = left(new Error('"npm publish" can not be run from root, run "npm run release" instead')) 5 | 6 | run(main) 7 | 8 | -------------------------------------------------------------------------------- /docs/modules/index.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: index.ts 3 | nav_order: 14 4 | parent: Modules 5 | --- 6 | 7 | # index overview 8 | 9 | Added in v0.5.8 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | --- 16 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint-config-standard", 3 | "rules": { 4 | "space-before-function-paren": false, 5 | "no-use-before-declare": false, 6 | "variable-name": false, 7 | "deprecation": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | remote_theme: pmarsceill/just-the-docs 2 | 3 | # Enable or disable the site search 4 | search_enabled: true 5 | 6 | # Aux links for the upper right navigation 7 | aux_links: 8 | 'io-ts-types on GitHub': 9 | - '//github.com/gcanti/io-ts-types' 10 | -------------------------------------------------------------------------------- /test/date.ts: -------------------------------------------------------------------------------- 1 | import { date } from '../src' 2 | import { assertFailure, assertSuccess } from './helpers' 3 | 4 | describe('Date', () => { 5 | it('decode', () => { 6 | const T = date 7 | assertSuccess(T.decode(new Date(0)), new Date(0)) 8 | assertFailure(T, 1, ['Invalid value 1 supplied to : Date']) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /test/withMessage.ts: -------------------------------------------------------------------------------- 1 | import * as t from 'io-ts' 2 | import { assertFailure } from './helpers' 3 | import { withMessage } from '../src' 4 | 5 | describe('withMessage', () => { 6 | it('should set the error message', () => { 7 | const T = withMessage(t.string, u => `${u} is not a string`) 8 | assertFailure(T, null, ['null is not a string']) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/fromRefinement.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.4 3 | */ 4 | import * as t from 'io-ts' 5 | 6 | /** 7 | * Returns a codec from a refinement 8 | * 9 | * @since 0.4.4 10 | */ 11 | export function fromRefinement(name: string, is: (u: unknown) => u is A): t.Type { 12 | return new t.Type(name, is, (u, c) => (is(u) ? t.success(u) : t.failure(u, c)), t.identity) 13 | } 14 | -------------------------------------------------------------------------------- /test/UUID.ts: -------------------------------------------------------------------------------- 1 | import { UUID } from '../src' 2 | import { assertFailure, assertSuccess } from './helpers' 3 | 4 | describe('UUID', () => { 5 | it('decode', () => { 6 | const T = UUID 7 | assertSuccess(T.decode('6e9c5587-a342-4b63-a901-87b31fa2ffa3'), '6e9c5587-a342-4b63-a901-87b31fa2ffa3' as UUID) 8 | assertFailure(UUID, 'a', ['Invalid value "a" supplied to : UUID']) 9 | }) 10 | }) 11 | -------------------------------------------------------------------------------- /src/date.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { fromRefinement } from './fromRefinement' 6 | 7 | /** 8 | * @since 0.5.0 9 | */ 10 | export interface DateC extends t.Type {} 11 | 12 | const isDate = (u: unknown): u is Date => u instanceof Date 13 | 14 | /** 15 | * @since 0.5.0 16 | */ 17 | export const date: DateC = fromRefinement('Date', isDate) 18 | -------------------------------------------------------------------------------- /test/BooleanFromString.ts: -------------------------------------------------------------------------------- 1 | import { BooleanFromString } from '../src' 2 | import { assertSuccess, assertFailure } from './helpers' 3 | 4 | describe('BooleanFromString', () => { 5 | it('decode', () => { 6 | const T = BooleanFromString 7 | assertSuccess(T.decode('true'), true) 8 | assertSuccess(T.decode('false'), false) 9 | assertFailure(T, 'a', ['Invalid value "a" supplied to : BooleanFromString']) 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /dtslint/ts3.5/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "strict": true, 5 | "noImplicitAny": true, 6 | "noImplicitThis": true, 7 | "strictNullChecks": true, 8 | "strictFunctionTypes": true, 9 | "noImplicitReturns": false, 10 | "noUnusedLocals": false, 11 | "noUnusedParameters": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "target": "es5", 14 | "lib": ["es2015"] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/BooleanFromNumber.ts: -------------------------------------------------------------------------------- 1 | import { BooleanFromNumber } from '../src' 2 | import { assertSuccess, assertFailure } from './helpers' 3 | 4 | describe('BooleanFromNumber', () => { 5 | it('decode', () => { 6 | const T = BooleanFromNumber 7 | assertSuccess(T.decode(0), false) 8 | assertSuccess(T.decode(1), true) 9 | assertSuccess(T.decode(123), true) 10 | assertFailure(T, 'a', ['Invalid value "a" supplied to : BooleanFromNumber']) 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /test/mapOutput.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import * as t from 'io-ts' 3 | import { mapOutput } from '../src' 4 | 5 | describe('mapOutput', () => { 6 | it('name', () => { 7 | const T = mapOutput(t.string, s => `(${s})`, 'T') 8 | assert.strictEqual(T.name, 'T') 9 | }) 10 | 11 | it('should map the output of encode', () => { 12 | const T = mapOutput(t.string, s => `(${s})`) 13 | assert.strictEqual(T.encode('a'), '(a)') 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /test/regexp.ts: -------------------------------------------------------------------------------- 1 | import { regexp } from '../src' 2 | import { assertSuccess, assertFailure } from './helpers' 3 | 4 | describe('RegExp', () => { 5 | it('should decode RegExp values', () => { 6 | assertSuccess(regexp.decode(/\w+/), /\w+/) 7 | assertSuccess(regexp.decode(new RegExp('\\w+')), new RegExp('\\w+')) 8 | }) 9 | 10 | it('should not decode non-Date values', () => { 11 | assertFailure(regexp, 1, ['Invalid value 1 supplied to : RegExp']) 12 | }) 13 | }) 14 | -------------------------------------------------------------------------------- /src/clone.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.3 3 | */ 4 | import * as t from 'io-ts' 5 | 6 | /** 7 | * Returns a clone of the given codec 8 | * 9 | * @example 10 | * import { clone } from 'io-ts-types/lib/clone' 11 | * import * as t from 'io-ts' 12 | * 13 | * assert.deepStrictEqual(clone(t.string), t.string) 14 | * 15 | * @since 0.4.3 16 | */ 17 | export function clone(t: C): C { 18 | const r = Object.create(Object.getPrototypeOf(t)) 19 | Object.assign(r, t) 20 | return r 21 | } 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Before submitting a pull request,** please make sure the following is done: 2 | 3 | - Fork [the repository](https://github.com/gcanti/io-ts-types) and create your branch from `master`. 4 | - Run `npm install` in the repository root. 5 | - If you've fixed a bug or added code that should be tested, add tests! 6 | - Ensure the test suite passes (`npm test`). 7 | 8 | **Note**. If you find a typo in the **documentation**, make sure to modify the corresponding source (docs are generated). 9 | -------------------------------------------------------------------------------- /scripts/run.ts: -------------------------------------------------------------------------------- 1 | import { fold } from 'fp-ts/Either' 2 | import { TaskEither } from 'fp-ts/TaskEither' 3 | 4 | export function run(eff: TaskEither): void { 5 | eff() 6 | .then( 7 | fold( 8 | (e) => { 9 | throw e 10 | }, 11 | (_) => { 12 | process.exitCode = 0 13 | } 14 | ) 15 | ) 16 | .catch((e) => { 17 | console.error(e) // tslint:disable-line no-console 18 | 19 | process.exitCode = 1 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | collectCoverage: true, 5 | collectCoverageFrom: ['src/**/*.ts'], 6 | transform: { 7 | '^.+\\.tsx?$': 'ts-jest' 8 | }, 9 | testRegex: 'test', 10 | moduleFileExtensions: ['ts', 'js'], 11 | testPathIgnorePatterns: ['helpers.ts'], 12 | coverageThreshold: { 13 | global: { 14 | branches: 100, 15 | functions: 100, 16 | lines: 100, 17 | statements: 100 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "noEmit": true, 4 | "sourceMap": true, 5 | "declaration": true, 6 | "module": "commonjs", 7 | "noImplicitReturns": false, 8 | "noUnusedLocals": true, 9 | "noUnusedParameters": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "noEmitOnError": false, 12 | "strict": true, 13 | "target": "es5", 14 | "moduleResolution": "node", 15 | "forceConsistentCasingInFileNames": true, 16 | "lib": ["es6"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/modules/fromRefinement.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: fromRefinement.ts 3 | nav_order: 12 4 | parent: Modules 5 | --- 6 | 7 | # fromRefinement overview 8 | 9 | Added in v0.4.4 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [fromRefinement](#fromrefinement) 16 | 17 | --- 18 | 19 | # fromRefinement 20 | 21 | Returns a codec from a refinement 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function fromRefinement
(name: string, is: (u: unknown) => u is A): t.Type { ... } 27 | ``` 28 | 29 | Added in v0.4.4 30 | -------------------------------------------------------------------------------- /test/fromNullable.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import * as t from 'io-ts' 3 | import { fromNullable } from '../src' 4 | import { assertFailure, assertSuccess } from './helpers' 5 | 6 | it('fromNullable', () => { 7 | const T = fromNullable(t.number, 0) 8 | assertSuccess(T.decode(42), 42) 9 | assertSuccess(T.decode(null), 0) 10 | assertSuccess(T.decode(undefined), 0) 11 | assertFailure(T, {}, ['Invalid value {} supplied to : fromNullable(number)']) 12 | const T2 = fromNullable(t.number, 0, 'T2') 13 | assert.strictEqual(T2.name, 'T2') 14 | }) 15 | -------------------------------------------------------------------------------- /docs/modules/date.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: date.ts 3 | nav_order: 5 4 | parent: Modules 5 | --- 6 | 7 | # date overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [DateC (interface)](#datec-interface) 16 | - [date](#date) 17 | 18 | --- 19 | 20 | # DateC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface DateC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.0 29 | 30 | # date 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const date: DateC = ... 36 | ``` 37 | 38 | Added in v0.5.0 39 | -------------------------------------------------------------------------------- /dtslint/ts3.5/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "dtslint/dtslint.json", 3 | "rules": { 4 | "semicolon": false, 5 | "array-type": false, 6 | "no-unnecessary-generics": false, 7 | "member-access": false, 8 | "no-empty-interface": false, 9 | "no-arg": false, 10 | "no-object-literal-type-assertion": false, 11 | "no-unnecessary-class": false, 12 | "radix": false, 13 | "no-angle-bracket-type-assertion": false, 14 | "object-literal-shorthand": false, 15 | "prefer-object-spread": false, 16 | "whitespace": false, 17 | "use-default-type-parameter": false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /docs/modules/clone.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: clone.ts 3 | nav_order: 4 4 | parent: Modules 5 | --- 6 | 7 | # clone overview 8 | 9 | Added in v0.4.3 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [clone](#clone) 16 | 17 | --- 18 | 19 | # clone 20 | 21 | Returns a clone of the given codec 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function clone(t: C): C { ... } 27 | ``` 28 | 29 | **Example** 30 | 31 | ```ts 32 | import { clone } from 'io-ts-types/lib/clone' 33 | import * as t from 'io-ts' 34 | 35 | assert.deepStrictEqual(clone(t.string), t.string) 36 | ``` 37 | 38 | Added in v0.4.3 39 | -------------------------------------------------------------------------------- /scripts/release.ts: -------------------------------------------------------------------------------- 1 | import { run } from './run' 2 | import * as child_process from 'child_process' 3 | import { left, right } from 'fp-ts/Either' 4 | import * as TE from 'fp-ts/TaskEither' 5 | 6 | const DIST = 'dist' 7 | 8 | const exec = (cmd: string, args?: child_process.ExecOptions): TE.TaskEither => () => 9 | new Promise((resolve) => { 10 | child_process.exec(cmd, args, (err) => { 11 | if (err !== null) { 12 | return resolve(left(err)) 13 | } 14 | 15 | return resolve(right(undefined)) 16 | }) 17 | }) 18 | 19 | export const main = exec('npm publish', { 20 | cwd: DIST 21 | }) 22 | 23 | run(main) 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist/lib", 4 | "noEmit": true, 5 | "esModuleInterop": true, 6 | "sourceMap": false, 7 | "declaration": true, 8 | "module": "commonjs", 9 | "strict": true, 10 | "noImplicitReturns": false, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": false, 13 | "noFallthroughCasesInSwitch": true, 14 | "noEmitOnError": false, 15 | "allowJs": false, 16 | "target": "es5", 17 | "moduleResolution": "node", 18 | "forceConsistentCasingInFileNames": true, 19 | "lib": ["es6", "dom", "ESNext.BigInt"] 20 | }, 21 | "include": ["./src/**/*"] 22 | } 23 | -------------------------------------------------------------------------------- /src/readonlySetFromArray.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.7 3 | */ 4 | import { Ord } from 'fp-ts/lib/Ord' 5 | import * as t from 'io-ts' 6 | import { setFromArray } from './setFromArray' 7 | 8 | /** 9 | * @since 0.5.7 10 | */ 11 | export interface ReadonlySetFromArrayC 12 | extends t.Type>, ReadonlyArray>, unknown> {} 13 | 14 | /** 15 | * @since 0.5.7 16 | */ 17 | export function readonlySetFromArray( 18 | codec: C, 19 | O: Ord>, 20 | name: string = `ReadonlySet<${codec.name}>` 21 | ): ReadonlySetFromArrayC { 22 | return setFromArray(codec, O, name) as any 23 | } 24 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [12.x] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - run: npm install 28 | - run: npm run build --if-present 29 | - run: npm test 30 | -------------------------------------------------------------------------------- /src/readonlyNonEmptyArray.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.7 3 | */ 4 | import * as t from 'io-ts' 5 | import { nonEmptyArray } from './nonEmptyArray' 6 | 7 | /** 8 | * @since 0.5.7 9 | */ 10 | export interface ReadonlyNonEmptyArray
extends ReadonlyArray { 11 | readonly 0: A 12 | } 13 | 14 | /** 15 | * @since 0.5.7 16 | */ 17 | export interface ReadonlyNonEmptyArrayC 18 | extends t.Type>, ReadonlyNonEmptyArray>, unknown> {} 19 | 20 | /** 21 | * @since 0.5.7 22 | */ 23 | export function readonlyNonEmptyArray( 24 | codec: C, 25 | name: string = `ReadonlyNonEmptyArray<${codec.name}>` 26 | ): ReadonlyNonEmptyArrayC { 27 | return nonEmptyArray(codec, name) as any 28 | } 29 | -------------------------------------------------------------------------------- /test/getLenses.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import * as t from 'io-ts' 3 | import { getLenses } from '../src' 4 | import { Lens } from 'monocle-ts' 5 | 6 | describe('getLenses', () => { 7 | it('type', () => { 8 | const T = t.type({ 9 | name: t.string, 10 | age: t.number 11 | }) 12 | const lenses = getLenses(T) 13 | assert.strictEqual(lenses.name instanceof Lens, true) 14 | assert.strictEqual(lenses.age instanceof Lens, true) 15 | }) 16 | 17 | it('strict', () => { 18 | const T = t.strict({ 19 | name: t.string, 20 | age: t.number 21 | }) 22 | const lenses = getLenses(T) 23 | assert.strictEqual(lenses.name instanceof Lens, true) 24 | assert.strictEqual(lenses.age instanceof Lens, true) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /src/readonlyMapFromEntries.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.19 3 | */ 4 | import { Ord } from 'fp-ts/lib/Ord' 5 | import * as t from 'io-ts' 6 | import { mapFromEntries } from './mapFromEntries' 7 | 8 | /** 9 | * @since 0.5.19 10 | */ 11 | export interface ReadonlyMapFromEntriesC 12 | extends t.Type, t.TypeOf>, ReadonlyArray<[t.OutputOf, t.OutputOf]>, unknown> {} 13 | 14 | /** 15 | * @since 0.5.19 16 | */ 17 | export function readonlyMapFromEntries( 18 | keyCodec: K, 19 | KO: Ord>, 20 | valueCodec: V, 21 | name: string = `ReadonlyMap<${keyCodec.name}, ${valueCodec.name}>` 22 | ): ReadonlyMapFromEntriesC { 23 | return mapFromEntries(keyCodec, KO, valueCodec, name) as any 24 | } 25 | -------------------------------------------------------------------------------- /src/regexp.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.4 3 | */ 4 | import * as t from 'io-ts' 5 | import { fromRefinement } from './fromRefinement' 6 | 7 | const isRegExp = (u: unknown): u is RegExp => Object.prototype.toString.call(u) === '[object RegExp]' 8 | 9 | /** 10 | * @since 0.4.4 11 | */ 12 | export interface RegExpC extends t.Type {} 13 | 14 | /** 15 | * @example 16 | * import { regexp } from 'io-ts-types/lib/regexp' 17 | * import { right } from 'fp-ts/lib/Either' 18 | * 19 | * const input1 = /\w+/ 20 | * const input2 = new RegExp('\\w+') 21 | * assert.deepStrictEqual(regexp.decode(input1), right(input1)) 22 | * assert.deepStrictEqual(regexp.decode(input2), right(input2)) 23 | * 24 | * @since 0.4.4 25 | */ 26 | export const regexp: RegExpC = fromRefinement('RegExp', isRegExp) 27 | -------------------------------------------------------------------------------- /test/readonlyNonEmptyArray.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { cons } from 'fp-ts/lib/NonEmptyArray' 3 | import * as t from 'io-ts' 4 | import { readonlyNonEmptyArray } from '../src' 5 | import { assertFailure, assertSuccess } from './helpers' 6 | 7 | describe('readonlyNonEmptyArray', () => { 8 | it('name', () => { 9 | const T = readonlyNonEmptyArray(t.number, 'T') 10 | assert.strictEqual(T.name, 'T') 11 | }) 12 | 13 | it('decode', () => { 14 | const T = readonlyNonEmptyArray(t.number) 15 | assertSuccess(T.decode([1]), cons(1, [])) 16 | assertSuccess(T.decode([1, 2, 3]), cons(1, [2, 3])) 17 | assertFailure(T, null, ['Invalid value null supplied to : ReadonlyNonEmptyArray']) 18 | assertFailure(T, [], ['Invalid value [] supplied to : ReadonlyNonEmptyArray']) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /test/NumberFromString.ts: -------------------------------------------------------------------------------- 1 | import { assertSuccess, assertFailure } from './helpers' 2 | import { NumberFromString } from '../src' 3 | 4 | describe('NumberFromString', () => { 5 | it('decode', () => { 6 | const T = NumberFromString 7 | assertSuccess(T.decode('0'), 0) 8 | assertSuccess(T.decode('10'), 10) 9 | assertSuccess(T.decode('-1'), -1) 10 | assertSuccess(T.decode('11'), 11) 11 | assertSuccess(T.decode('5.5'), 5.5) 12 | assertSuccess(T.decode('-5.5'), -5.5) 13 | assertFailure(T, '', ['Invalid value "" supplied to : NumberFromString']) 14 | assertFailure(T, ' ', ['Invalid value " " supplied to : NumberFromString']) 15 | assertFailure(T, 'a', ['Invalid value "a" supplied to : NumberFromString']) 16 | assertFailure(T, 'a5', ['Invalid value "a5" supplied to : NumberFromString']) 17 | }) 18 | }) 19 | -------------------------------------------------------------------------------- /docs/modules/setFromArray.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: setFromArray.ts 3 | nav_order: 28 4 | parent: Modules 5 | --- 6 | 7 | # setFromArray overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [SetFromArrayC (interface)](#setfromarrayc-interface) 16 | - [setFromArray](#setfromarray) 17 | 18 | --- 19 | 20 | # SetFromArrayC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface SetFromArrayC extends t.Type>, Array>, unknown> {} 26 | ``` 27 | 28 | Added in v0.5.0 29 | 30 | # setFromArray 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export function setFromArray( 36 | codec: C, 37 | O: Ord>, 38 | name: string = `Set<${codec.name}>` 39 | ): SetFromArrayC { ... } 40 | ``` 41 | 42 | Added in v0.5.0 43 | -------------------------------------------------------------------------------- /test/DateFromISOString.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { DateFromISOString } from '../src' 3 | import { assertFailure, assertSuccess } from './helpers' 4 | 5 | const d = new Date(1973, 10, 30) 6 | const s = d.toISOString() 7 | 8 | describe('DateFromISOString', () => { 9 | it('is', () => { 10 | const T = DateFromISOString 11 | assert.strictEqual(T.is(d), true) 12 | }) 13 | 14 | it('decode', () => { 15 | const T = DateFromISOString 16 | assertSuccess(T.decode(s), d) 17 | assertFailure(T, null, ['Invalid value null supplied to : DateFromISOString']) 18 | assertFailure(T, 'foo', ['Invalid value "foo" supplied to : DateFromISOString']) 19 | assert.deepStrictEqual(T.decode(d)._tag, 'Left') 20 | }) 21 | 22 | it('encode', () => { 23 | const T = DateFromISOString 24 | assert.strictEqual(T.encode(d), s) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /docs/modules/nonEmptyArray.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: nonEmptyArray.ts 3 | nav_order: 19 4 | parent: Modules 5 | --- 6 | 7 | # nonEmptyArray overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [NonEmptyArrayC (interface)](#nonemptyarrayc-interface) 16 | - [nonEmptyArray](#nonemptyarray) 17 | 18 | --- 19 | 20 | # NonEmptyArrayC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface NonEmptyArrayC 26 | extends t.Type>, NonEmptyArray>, unknown> {} 27 | ``` 28 | 29 | Added in v0.5.0 30 | 31 | # nonEmptyArray 32 | 33 | **Signature** 34 | 35 | ```ts 36 | export function nonEmptyArray( 37 | codec: C, 38 | name: string = `NonEmptyArray<${codec.name}>` 39 | ): NonEmptyArrayC { ... } 40 | ``` 41 | 42 | Added in v0.5.0 43 | -------------------------------------------------------------------------------- /src/withFallback.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { withValidate } from './withValidate' 6 | import { orElse } from 'fp-ts/lib/Either' 7 | 8 | /** 9 | * Returns a clone of the given codec that always succeed using the given value `a` if the original codec fails 10 | * 11 | * @example 12 | * import { withFallback } from 'io-ts-types/lib/withFallback' 13 | * import * as t from 'io-ts' 14 | * import { right } from 'fp-ts/lib/Either' 15 | * 16 | * const T = withFallback(t.number, -1) 17 | * 18 | * assert.deepStrictEqual(T.decode(1), right(1)) 19 | * assert.deepStrictEqual(T.decode('a'), right(-1)) 20 | * 21 | * @since 0.5.0 22 | */ 23 | export function withFallback(codec: C, a: t.TypeOf, name = `withFallback(${codec.name})`): C { 24 | return withValidate(codec, (u, c) => orElse(() => t.success(a))(codec.validate(u, c)), name) 25 | } 26 | -------------------------------------------------------------------------------- /docs/modules/optionFromNullable.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: optionFromNullable.ts 3 | nav_order: 23 4 | parent: Modules 5 | --- 6 | 7 | # optionFromNullable overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [OptionFromNullableC (interface)](#optionfromnullablec-interface) 16 | - [optionFromNullable](#optionfromnullable) 17 | 18 | --- 19 | 20 | # OptionFromNullableC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface OptionFromNullableC 26 | extends t.Type>, t.OutputOf | null, unknown> {} 27 | ``` 28 | 29 | Added in v0.5.0 30 | 31 | # optionFromNullable 32 | 33 | **Signature** 34 | 35 | ```ts 36 | export function optionFromNullable( 37 | codec: C, 38 | name: string = `Option<${codec.name}>` 39 | ): OptionFromNullableC { ... } 40 | ``` 41 | 42 | Added in v0.5.0 43 | -------------------------------------------------------------------------------- /test/IntFromString.ts: -------------------------------------------------------------------------------- 1 | import { IntFromString } from '../src' 2 | import { assertSuccess, assertFailure } from './helpers' 3 | import * as t from 'io-ts' 4 | 5 | const zero: t.Int = 0 as any 6 | const one: t.Int = 1 as any 7 | 8 | describe('IntFromString', () => { 9 | it('decode', () => { 10 | const T = IntFromString 11 | assertSuccess(T.decode('0'), zero) 12 | assertSuccess(T.decode('1'), one) 13 | assertFailure(T, 'a', ['Invalid value "a" supplied to : IntFromString']) 14 | assertFailure(T, '2a', ['Invalid value "2a" supplied to : IntFromString']) 15 | assertFailure(T, '2.a', ['Invalid value "2.a" supplied to : IntFromString']) 16 | assertFailure(T, '1.1', ['Invalid value "1.1" supplied to : IntFromString']) 17 | assertFailure(T, '', ['Invalid value "" supplied to : IntFromString']) 18 | assertFailure(T, ' ', ['Invalid value " " supplied to : IntFromString']) 19 | }) 20 | }) 21 | -------------------------------------------------------------------------------- /src/NumberFromString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { pipe } from 'fp-ts/lib/pipeable' 6 | import { chain } from 'fp-ts/lib/Either' 7 | 8 | /** 9 | * @since 0.5.0 10 | */ 11 | export interface NumberFromStringC extends t.Type {} 12 | 13 | /** 14 | * @example 15 | * import { NumberFromString } from 'io-ts-types/lib/NumberFromString' 16 | * 17 | * NumberFromString.decode('1') // right(1) 18 | * NumberFromString.decode('1.1') // right(1.1) 19 | * 20 | * @since 0.5.0 21 | */ 22 | export const NumberFromString: NumberFromStringC = new t.Type( 23 | 'NumberFromString', 24 | t.number.is, 25 | (u, c) => 26 | pipe( 27 | t.string.validate(u, c), 28 | chain(s => { 29 | const n = +s 30 | return isNaN(n) || s.trim() === '' ? t.failure(u, c) : t.success(n) 31 | }) 32 | ), 33 | String 34 | ) 35 | -------------------------------------------------------------------------------- /test/withEncode.ts: -------------------------------------------------------------------------------- 1 | import * as t from 'io-ts' 2 | import * as assert from 'assert' 3 | import { withEncode } from '../src' 4 | import { assertSuccess, assertFailure } from './helpers' 5 | 6 | describe('withEncode', () => { 7 | it('is', () => { 8 | const T = withEncode(t.number, String) 9 | assert.strictEqual(T.is(5), true) 10 | assert.strictEqual(T.is(null), false) 11 | }) 12 | it('decode', () => { 13 | const T = withEncode(t.number, String, 'MyCodec') 14 | assertSuccess(T.decode(0), 0) 15 | assertSuccess(T.decode(10), 10) 16 | assertSuccess(T.decode(-1), -1) 17 | assertSuccess(T.decode(11), 11) 18 | assertFailure(T, '', ['Invalid value "" supplied to : MyCodec']) 19 | assertFailure(T, 'a', ['Invalid value "a" supplied to : MyCodec']) 20 | }) 21 | it('encode', () => { 22 | const T = withEncode(t.number, String) 23 | assert.strictEqual(T.encode(5), '5') 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /test/DateFromNumber.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { DateFromNumber } from '../src' 3 | import { assertSuccess, assertFailure } from './helpers' 4 | import { either } from 'fp-ts/lib/Either' 5 | 6 | const d = new Date(1973, 10, 30) 7 | const n = d.getTime() 8 | 9 | describe('DateFromNumber', () => { 10 | it('is', () => { 11 | const T = DateFromNumber 12 | assert.strictEqual(T.is(d), true) 13 | assert.strictEqual(T.is(0), false) 14 | }) 15 | 16 | it('decode', () => { 17 | const T = DateFromNumber 18 | assertSuccess(T.decode(n), d) 19 | assertSuccess(either.map(T.decode(n), d => d.getTime()), n) 20 | assertFailure(T, NaN, ['Invalid value NaN supplied to : DateFromNumber']) 21 | assertFailure(T, '', ['Invalid value "" supplied to : DateFromNumber']) 22 | }) 23 | 24 | it('encode', () => { 25 | const T = DateFromNumber 26 | assert.strictEqual(T.encode(d), n) 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /src/withEncode.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.12 3 | */ 4 | import * as t from 'io-ts' 5 | 6 | /** 7 | * Returns a clone of the given codec which uses the given `encode` function 8 | * 9 | * @example 10 | * import { withEncode } from 'io-ts-types/lib/withEncode' 11 | * import * as t from 'io-ts' 12 | * import { PathReporter } from 'io-ts/lib/PathReporter' 13 | * import { right } from 'fp-ts/lib/Either' 14 | * 15 | * const T = withEncode(t.number, String) 16 | * 17 | * assert.deepStrictEqual(T.decode(1), right(1)) 18 | * assert.deepStrictEqual(T.encode(1), '1') 19 | * assert.deepStrictEqual(PathReporter.report(T.decode('str')), ['Invalid value "str" supplied to : number']) 20 | * 21 | * @since 0.5.12 22 | */ 23 | export function withEncode( 24 | codec: t.Type, 25 | encode: (a: A) => P, 26 | name: string = codec.name 27 | ): t.Type { 28 | return new t.Type(name, codec.is, codec.validate, encode) 29 | } 30 | -------------------------------------------------------------------------------- /src/UUID.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.6 3 | */ 4 | import * as t from 'io-ts' 5 | 6 | const regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i 7 | 8 | /** 9 | * @since 0.4.6 10 | */ 11 | export interface UUIDBrand { 12 | readonly UUID: unique symbol 13 | } 14 | 15 | /** 16 | * @since 0.4.6 17 | */ 18 | export type UUID = t.Branded 19 | 20 | /** 21 | * @example 22 | * import { UUID } from 'io-ts-types/lib/UUID' 23 | * import { right } from 'fp-ts/lib/Either' 24 | * import { PathReporter } from 'io-ts/lib/PathReporter' 25 | * 26 | * assert.deepStrictEqual(UUID.decode('00000000-0000-0000-0000-000000000000'), right('00000000-0000-0000-0000-000000000000')) 27 | * assert.deepStrictEqual(PathReporter.report(UUID.decode('not a uuid')), ['Invalid value "not a uuid" supplied to : UUID']) 28 | * 29 | * @since 0.4.6 30 | */ 31 | export const UUID = t.brand(t.string, (s): s is UUID => regex.test(s), 'UUID') 32 | -------------------------------------------------------------------------------- /docs/modules/NumberFromString.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: NumberFromString.ts 3 | nav_order: 21 4 | parent: Modules 5 | --- 6 | 7 | # NumberFromString overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [NumberFromStringC (interface)](#numberfromstringc-interface) 16 | - [NumberFromString](#numberfromstring) 17 | 18 | --- 19 | 20 | # NumberFromStringC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface NumberFromStringC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.0 29 | 30 | # NumberFromString 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const NumberFromString: NumberFromStringC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { NumberFromString } from 'io-ts-types/lib/NumberFromString' 42 | 43 | NumberFromString.decode('1') // right(1) 44 | NumberFromString.decode('1.1') // right(1.1) 45 | ``` 46 | 47 | Added in v0.5.0 48 | -------------------------------------------------------------------------------- /docs/modules/regexp.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: regexp.ts 3 | nav_order: 27 4 | parent: Modules 5 | --- 6 | 7 | # regexp overview 8 | 9 | Added in v0.4.4 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [RegExpC (interface)](#regexpc-interface) 16 | - [regexp](#regexp) 17 | 18 | --- 19 | 20 | # RegExpC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface RegExpC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.4.4 29 | 30 | # regexp 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const regexp: RegExpC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { regexp } from 'io-ts-types/lib/regexp' 42 | import { right } from 'fp-ts/lib/Either' 43 | 44 | const input1 = /\w+/ 45 | const input2 = new RegExp('\\w+') 46 | assert.deepStrictEqual(regexp.decode(input1), right(input1)) 47 | assert.deepStrictEqual(regexp.decode(input2), right(input2)) 48 | ``` 49 | 50 | Added in v0.4.4 51 | -------------------------------------------------------------------------------- /docs/modules/withFallback.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: withFallback.ts 3 | nav_order: 31 4 | parent: Modules 5 | --- 6 | 7 | # withFallback overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [withFallback](#withfallback) 16 | 17 | --- 18 | 19 | # withFallback 20 | 21 | Returns a clone of the given codec that always succeed using the given value `a` if the original codec fails 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function withFallback(codec: C, a: t.TypeOf, name = `withFallback(${codec.name})`): C { ... } 27 | ``` 28 | 29 | **Example** 30 | 31 | ```ts 32 | import { withFallback } from 'io-ts-types/lib/withFallback' 33 | import * as t from 'io-ts' 34 | import { right } from 'fp-ts/lib/Either' 35 | 36 | const T = withFallback(t.number, -1) 37 | 38 | assert.deepStrictEqual(T.decode(1), right(1)) 39 | assert.deepStrictEqual(T.decode('a'), right(-1)) 40 | ``` 41 | 42 | Added in v0.5.0 43 | -------------------------------------------------------------------------------- /docs/modules/readonlySetFromArray.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: readonlySetFromArray.ts 3 | nav_order: 26 4 | parent: Modules 5 | --- 6 | 7 | # readonlySetFromArray overview 8 | 9 | Added in v0.5.7 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [ReadonlySetFromArrayC (interface)](#readonlysetfromarrayc-interface) 16 | - [readonlySetFromArray](#readonlysetfromarray) 17 | 18 | --- 19 | 20 | # ReadonlySetFromArrayC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface ReadonlySetFromArrayC 26 | extends t.Type>, ReadonlyArray>, unknown> {} 27 | ``` 28 | 29 | Added in v0.5.7 30 | 31 | # readonlySetFromArray 32 | 33 | **Signature** 34 | 35 | ```ts 36 | export function readonlySetFromArray( 37 | codec: C, 38 | O: Ord>, 39 | name: string = `ReadonlySet<${codec.name}>` 40 | ): ReadonlySetFromArrayC { ... } 41 | ``` 42 | 43 | Added in v0.5.7 44 | -------------------------------------------------------------------------------- /test/readonlySetFromArray.ts: -------------------------------------------------------------------------------- 1 | import { readonlySetFromArray } from '../src' 2 | import * as t from 'io-ts' 3 | import * as assert from 'assert' 4 | import { assertFailure, assertSuccess } from './helpers' 5 | import { ordNumber } from 'fp-ts/lib/Ord' 6 | 7 | describe('readonlySetFromArray', () => { 8 | it('name', () => { 9 | const T = readonlySetFromArray(t.number, ordNumber, 'T') 10 | assert.strictEqual(T.name, 'T') 11 | }) 12 | 13 | it('decode', () => { 14 | const T = readonlySetFromArray(t.number, ordNumber) 15 | assertSuccess(T.decode([]), new Set()) 16 | assertSuccess(T.decode([1]), new Set([1])) 17 | assertSuccess(T.decode([1, 2, 3]), new Set([1, 2, 3])) 18 | assertFailure(T, [1, 1], ['Invalid value [1,1] supplied to : ReadonlySet']) 19 | assertFailure(T, null, ['Invalid value null supplied to : ReadonlySet']) 20 | assertFailure(T, [1, 'a'], ['Invalid value "a" supplied to : ReadonlySet/1: number']) 21 | }) 22 | }) 23 | -------------------------------------------------------------------------------- /docs/modules/mapFromEntries.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: mapFromEntries.ts 3 | nav_order: 17 4 | parent: Modules 5 | --- 6 | 7 | # mapFromEntries overview 8 | 9 | Added in v0.5.19 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [MapFromEntriesC (interface)](#mapfromentriesc-interface) 16 | - [mapFromEntries](#mapfromentries) 17 | 18 | --- 19 | 20 | # MapFromEntriesC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface MapFromEntriesC 26 | extends t.Type, t.TypeOf>, Array<[t.OutputOf, t.OutputOf]>, unknown> {} 27 | ``` 28 | 29 | Added in v0.5.19 30 | 31 | # mapFromEntries 32 | 33 | **Signature** 34 | 35 | ```ts 36 | export function mapFromEntries( 37 | keyCodec: K, 38 | KO: Ord>, 39 | valueCodec: V, 40 | name: string = `Map<${keyCodec.name}, ${valueCodec.name}>` 41 | ): MapFromEntriesC { ... } 42 | ``` 43 | 44 | Added in v0.5.19 45 | -------------------------------------------------------------------------------- /docs/modules/DateFromNumber.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DateFromNumber.ts 3 | nav_order: 7 4 | parent: Modules 5 | --- 6 | 7 | # DateFromNumber overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [DateFromNumberC (interface)](#datefromnumberc-interface) 16 | - [DateFromNumber](#datefromnumber) 17 | 18 | --- 19 | 20 | # DateFromNumberC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface DateFromNumberC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.0 29 | 30 | # DateFromNumber 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const DateFromNumber: DateFromNumberC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { DateFromNumber } from 'io-ts-types/lib/DateFromNumber' 42 | import { right } from 'fp-ts/lib/Either' 43 | 44 | const date = new Date(1973, 10, 30) 45 | const input = date.getTime() 46 | assert.deepStrictEqual(DateFromNumber.decode(input), right(date)) 47 | ``` 48 | 49 | Added in v0.5.0 50 | -------------------------------------------------------------------------------- /src/optionFromNullable.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import { pipe } from 'fp-ts/lib/pipeable' 5 | import { map } from 'fp-ts/lib/Either' 6 | import * as O from 'fp-ts/lib/Option' 7 | import * as t from 'io-ts' 8 | import { option } from './option' 9 | 10 | /** 11 | * @since 0.5.0 12 | */ 13 | export interface OptionFromNullableC 14 | extends t.Type>, t.OutputOf | null, unknown> {} 15 | 16 | /** 17 | * @since 0.5.0 18 | */ 19 | export function optionFromNullable( 20 | codec: C, 21 | name: string = `Option<${codec.name}>` 22 | ): OptionFromNullableC { 23 | return new t.Type( 24 | name, 25 | option(codec).is, 26 | (u, c) => 27 | u == null 28 | ? t.success(O.none) 29 | : pipe( 30 | codec.validate(u, c), 31 | map(O.some) 32 | ), 33 | a => 34 | O.toNullable( 35 | pipe( 36 | a, 37 | O.map(codec.encode) 38 | ) 39 | ) 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /src/DateFromNumber.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { pipe } from 'fp-ts/lib/pipeable' 6 | import { chain } from 'fp-ts/lib/Either' 7 | 8 | /** 9 | * @since 0.5.0 10 | */ 11 | export interface DateFromNumberC extends t.Type {} 12 | 13 | /** 14 | * @example 15 | * import { DateFromNumber } from 'io-ts-types/lib/DateFromNumber' 16 | * import { right } from 'fp-ts/lib/Either' 17 | * 18 | * const date = new Date(1973, 10, 30) 19 | * const input = date.getTime() 20 | * assert.deepStrictEqual(DateFromNumber.decode(input), right(date)) 21 | * 22 | * @since 0.5.0 23 | */ 24 | export const DateFromNumber: DateFromNumberC = new t.Type( 25 | 'DateFromNumber', 26 | (u): u is Date => u instanceof Date, 27 | (u, c) => 28 | pipe( 29 | t.number.validate(u, c), 30 | chain(n => { 31 | const d = new Date(n) 32 | return isNaN(d.getTime()) ? t.failure(u, c) : t.success(d) 33 | }) 34 | ), 35 | a => a.getTime() 36 | ) 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F41B Bug report" 3 | about: Create a report to help make io-ts-types better 4 | --- 5 | 6 | ## 🐛 Bug report 7 | 8 | ### Current Behavior 9 | 10 | 11 | 12 | ### Expected behavior 13 | 14 | 15 | 16 | ### Reproducible example 17 | 18 | ### Suggested solution(s) 19 | 20 | 21 | 22 | ### Additional context 23 | 24 | 25 | 26 | ### Your environment 27 | 28 | Which versions of io-ts-types are affected by this issue? Did this work in previous versions of io-ts-types? 29 | 30 | 31 | 32 | | Software | Version(s) | 33 | | ----------- | ---------- | 34 | | fp-ts | | 35 | | io-ts | | 36 | | io-ts-types | | 37 | | TypeScript | | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A collection of runtime types and combinators for use with [io-ts](https://github.com/gcanti/io-ts) 2 | 3 | # Installation 4 | 5 | To install the stable version: 6 | 7 | ```sh 8 | npm i io-ts-types 9 | ``` 10 | 11 | **Note**. `io-ts-types` depends on 12 | 13 | - [`fp-ts`](https://github.com/gcanti/fp-ts) 14 | - [`io-ts`](https://github.com/gcanti/io-ts) 15 | - [`monocle-ts`](https://github.com/gcanti/monocle-ts) 16 | - [`newtype-ts`](https://github.com/gcanti/newtype-ts) 17 | 18 | starting from `0.5.0` you must install `fp-ts`, `io-ts`, `newtype-ts` and `monocle-ts` manually (`fp-ts`, `io-ts`, `newtype-ts` and `monocle-ts` are listed in `peerDependency`) 19 | 20 | # TypeScript compatibility 21 | 22 | | `io-ts-types` version | required `typescript` version | 23 | | --------------------- | ----------------------------- | 24 | | 0.5.x | 3.5+ | 25 | | 0.4.x | 3.1+ | 26 | 27 | # Documentation 28 | 29 | - [API Reference](https://gcanti.github.io/io-ts-types) 30 | -------------------------------------------------------------------------------- /docs/modules/withMessage.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: withMessage.ts 3 | nav_order: 32 4 | parent: Modules 5 | --- 6 | 7 | # withMessage overview 8 | 9 | Added in v0.4.3 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [withMessage](#withmessage) 16 | 17 | --- 18 | 19 | # withMessage 20 | 21 | Returns a clone of the given codec that sets the given string as error messsage 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function withMessage(codec: C, message: (i: t.InputOf, c: t.Context) => string): C { ... } 27 | ``` 28 | 29 | **Example** 30 | 31 | ```ts 32 | import { withMessage } from 'io-ts-types/lib/withMessage' 33 | import * as t from 'io-ts' 34 | import { PathReporter } from 'io-ts/lib/PathReporter' 35 | import { right } from 'fp-ts/lib/Either' 36 | 37 | const T = withMessage(t.number, () => 'Invalid number') 38 | 39 | assert.deepStrictEqual(T.decode(1), right(1)) 40 | assert.deepStrictEqual(PathReporter.report(T.decode(null)), ['Invalid number']) 41 | ``` 42 | 43 | Added in v0.4.3 44 | -------------------------------------------------------------------------------- /docs/modules/DateFromUnixTime.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DateFromUnixTime.ts 3 | nav_order: 8 4 | parent: Modules 5 | --- 6 | 7 | # DateFromUnixTime overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [DateFromUnixTimeC (interface)](#datefromunixtimec-interface) 16 | - [DateFromUnixTime](#datefromunixtime) 17 | 18 | --- 19 | 20 | # DateFromUnixTimeC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface DateFromUnixTimeC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.0 29 | 30 | # DateFromUnixTime 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const DateFromUnixTime: DateFromUnixTimeC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { DateFromUnixTime } from 'io-ts-types/lib/DateFromUnixTime' 42 | import { right } from 'fp-ts/lib/Either' 43 | 44 | const date = new Date(1973, 10, 30) 45 | const input = date.getTime() / 1000 46 | assert.deepStrictEqual(DateFromUnixTime.decode(input), right(date)) 47 | ``` 48 | 49 | Added in v0.5.0 50 | -------------------------------------------------------------------------------- /src/DateFromISOString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { pipe } from 'fp-ts/lib/pipeable' 6 | import { chain } from 'fp-ts/lib/Either' 7 | 8 | /** 9 | * @since 0.5.0 10 | */ 11 | export interface DateFromISOStringC extends t.Type {} 12 | 13 | /** 14 | * @example 15 | * import { DateFromISOString } from 'io-ts-types/lib/DateFromISOString' 16 | * import { right } from 'fp-ts/lib/Either' 17 | * 18 | * const date = new Date(1973, 10, 30) 19 | * const input = date.toISOString() 20 | * assert.deepStrictEqual(DateFromISOString.decode(input), right(date)) 21 | * 22 | * @since 0.5.0 23 | */ 24 | export const DateFromISOString: DateFromISOStringC = new t.Type( 25 | 'DateFromISOString', 26 | (u): u is Date => u instanceof Date, 27 | (u, c) => 28 | pipe( 29 | t.string.validate(u, c), 30 | chain(s => { 31 | const d = new Date(s) 32 | return isNaN(d.getTime()) ? t.failure(u, c) : t.success(d) 33 | }) 34 | ), 35 | a => a.toISOString() 36 | ) 37 | -------------------------------------------------------------------------------- /docs/modules/DateFromISOString.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DateFromISOString.ts 3 | nav_order: 6 4 | parent: Modules 5 | --- 6 | 7 | # DateFromISOString overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [DateFromISOStringC (interface)](#datefromisostringc-interface) 16 | - [DateFromISOString](#datefromisostring) 17 | 18 | --- 19 | 20 | # DateFromISOStringC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface DateFromISOStringC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.0 29 | 30 | # DateFromISOString 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const DateFromISOString: DateFromISOStringC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { DateFromISOString } from 'io-ts-types/lib/DateFromISOString' 42 | import { right } from 'fp-ts/lib/Either' 43 | 44 | const date = new Date(1973, 10, 30) 45 | const input = date.toISOString() 46 | assert.deepStrictEqual(DateFromISOString.decode(input), right(date)) 47 | ``` 48 | 49 | Added in v0.5.0 50 | -------------------------------------------------------------------------------- /src/DateFromUnixTime.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { pipe } from 'fp-ts/lib/pipeable' 6 | import { chain } from 'fp-ts/lib/Either' 7 | 8 | /** 9 | * @since 0.5.0 10 | */ 11 | export interface DateFromUnixTimeC extends t.Type {} 12 | 13 | /** 14 | * @example 15 | * import { DateFromUnixTime } from 'io-ts-types/lib/DateFromUnixTime' 16 | * import { right } from 'fp-ts/lib/Either' 17 | * 18 | * const date = new Date(1973, 10, 30) 19 | * const input = date.getTime() / 1000 20 | * assert.deepStrictEqual(DateFromUnixTime.decode(input), right(date)) 21 | * 22 | * @since 0.5.0 23 | */ 24 | export const DateFromUnixTime: DateFromUnixTimeC = new t.Type( 25 | 'DateFromUnixTime', 26 | (u): u is Date => u instanceof Date, 27 | (u, c) => 28 | pipe( 29 | t.Int.validate(u, c), 30 | chain(n => { 31 | const d = new Date(n * 1000) 32 | return isNaN(d.getTime()) ? t.failure(u, c) : t.success(d) 33 | }) 34 | ), 35 | a => Math.floor(a.getTime() / 1000) 36 | ) 37 | -------------------------------------------------------------------------------- /src/fromNullable.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { withValidate } from './withValidate' 6 | 7 | /** 8 | * Returns a clone of the given codec that replace a nullable input with the given value `a` 9 | * 10 | * @example 11 | * import { fromNullable } from 'io-ts-types/lib/fromNullable' 12 | * import * as t from 'io-ts' 13 | * import { right } from 'fp-ts/lib/Either' 14 | * import { PathReporter } from 'io-ts/lib/PathReporter' 15 | * 16 | * const T = fromNullable(t.number, -1) 17 | * 18 | * assert.deepStrictEqual(T.decode(1), right(1)) 19 | * assert.deepStrictEqual(T.decode(null), right(-1)) 20 | * assert.deepStrictEqual(T.decode(undefined), right(-1)) 21 | * assert.deepStrictEqual(PathReporter.report(T.decode('a')), ['Invalid value "a" supplied to : fromNullable(number)']) 22 | * 23 | * @since 0.5.0 24 | */ 25 | export function fromNullable(codec: C, a: t.TypeOf, name = `fromNullable(${codec.name})`): C { 26 | return withValidate(codec, (u, c) => (u == null ? t.success(a) : codec.validate(u, c)), name) 27 | } 28 | -------------------------------------------------------------------------------- /src/withValidate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.3 3 | */ 4 | import * as t from 'io-ts' 5 | import { clone } from './clone' 6 | 7 | /** 8 | * Returns a clone of the given codec which uses the given `validate` function 9 | * 10 | * @example 11 | * import { withValidate } from 'io-ts-types/lib/withValidate' 12 | * import * as t from 'io-ts' 13 | * import { PathReporter } from 'io-ts/lib/PathReporter' 14 | * import { either, right } from 'fp-ts/lib/Either' 15 | * 16 | * const T = withValidate(t.number, (u, c) => either.map(t.number.validate(u, c), n => n * 2)) 17 | * 18 | * assert.deepStrictEqual(T.decode(1), right(2)) 19 | * assert.deepStrictEqual(PathReporter.report(T.decode(null)), ['Invalid value null supplied to : number']) 20 | * 21 | * @since 0.4.3 22 | */ 23 | export function withValidate(codec: C, validate: C['validate'], name: string = codec.name): C { 24 | const r: any = clone(codec) 25 | r.validate = validate 26 | // tslint:disable-next-line: deprecation 27 | r.decode = (i: any) => validate(i, t.getDefaultContext(r)) 28 | r.name = name 29 | return r 30 | } 31 | -------------------------------------------------------------------------------- /docs/modules/withValidate.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: withValidate.ts 3 | nav_order: 33 4 | parent: Modules 5 | --- 6 | 7 | # withValidate overview 8 | 9 | Added in v0.4.3 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [withValidate](#withvalidate) 16 | 17 | --- 18 | 19 | # withValidate 20 | 21 | Returns a clone of the given codec which uses the given `validate` function 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function withValidate(codec: C, validate: C['validate'], name: string = codec.name): C { ... } 27 | ``` 28 | 29 | **Example** 30 | 31 | ```ts 32 | import { withValidate } from 'io-ts-types/lib/withValidate' 33 | import * as t from 'io-ts' 34 | import { PathReporter } from 'io-ts/lib/PathReporter' 35 | import { either, right } from 'fp-ts/lib/Either' 36 | 37 | const T = withValidate(t.number, (u, c) => either.map(t.number.validate(u, c), n => n * 2)) 38 | 39 | assert.deepStrictEqual(T.decode(1), right(2)) 40 | assert.deepStrictEqual(PathReporter.report(T.decode(null)), ['Invalid value null supplied to : number']) 41 | ``` 42 | 43 | Added in v0.4.3 44 | -------------------------------------------------------------------------------- /docs/modules/readonlyMapFromEntries.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: readonlyMapFromEntries.ts 3 | nav_order: 24 4 | parent: Modules 5 | --- 6 | 7 | # readonlyMapFromEntries overview 8 | 9 | Added in v0.5.19 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [ReadonlyMapFromEntriesC (interface)](#readonlymapfromentriesc-interface) 16 | - [readonlyMapFromEntries](#readonlymapfromentries) 17 | 18 | --- 19 | 20 | # ReadonlyMapFromEntriesC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface ReadonlyMapFromEntriesC 26 | extends t.Type, t.TypeOf>, ReadonlyArray<[t.OutputOf, t.OutputOf]>, unknown> {} 27 | ``` 28 | 29 | Added in v0.5.19 30 | 31 | # readonlyMapFromEntries 32 | 33 | **Signature** 34 | 35 | ```ts 36 | export function readonlyMapFromEntries( 37 | keyCodec: K, 38 | KO: Ord>, 39 | valueCodec: V, 40 | name: string = `ReadonlyMap<${keyCodec.name}, ${valueCodec.name}>` 41 | ): ReadonlyMapFromEntriesC { ... } 42 | ``` 43 | 44 | Added in v0.5.19 45 | -------------------------------------------------------------------------------- /src/withMessage.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.3 3 | */ 4 | import * as t from 'io-ts' 5 | import { withValidate } from './withValidate' 6 | import { mapLeft } from 'fp-ts/lib/Either' 7 | 8 | /** 9 | * Returns a clone of the given codec that sets the given string as error messsage 10 | * 11 | * @example 12 | * import { withMessage } from 'io-ts-types/lib/withMessage' 13 | * import * as t from 'io-ts' 14 | * import { PathReporter } from 'io-ts/lib/PathReporter' 15 | * import { right } from 'fp-ts/lib/Either' 16 | * 17 | * const T = withMessage(t.number, () => 'Invalid number') 18 | * 19 | * assert.deepStrictEqual(T.decode(1), right(1)) 20 | * assert.deepStrictEqual(PathReporter.report(T.decode(null)), ['Invalid number']) 21 | * 22 | * @since 0.4.3 23 | */ 24 | export function withMessage(codec: C, message: (i: t.InputOf, c: t.Context) => string): C { 25 | return withValidate(codec, (i, c) => 26 | mapLeft(() => [ 27 | { 28 | value: i, 29 | context: c, 30 | message: message(i, c), 31 | actual: i 32 | } 33 | ])(codec.validate(i, c)) 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /docs/modules/withEncode.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: withEncode.ts 3 | nav_order: 30 4 | parent: Modules 5 | --- 6 | 7 | # withEncode overview 8 | 9 | Added in v0.5.12 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [withEncode](#withencode) 16 | 17 | --- 18 | 19 | # withEncode 20 | 21 | Returns a clone of the given codec which uses the given `encode` function 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function withEncode( 27 | codec: t.Type, 28 | encode: (a: A) => P, 29 | name: string = codec.name 30 | ): t.Type { ... } 31 | ``` 32 | 33 | **Example** 34 | 35 | ```ts 36 | import { withEncode } from 'io-ts-types/lib/withEncode' 37 | import * as t from 'io-ts' 38 | import { PathReporter } from 'io-ts/lib/PathReporter' 39 | import { right } from 'fp-ts/lib/Either' 40 | 41 | const T = withEncode(t.number, String) 42 | 43 | assert.deepStrictEqual(T.decode(1), right(1)) 44 | assert.deepStrictEqual(T.encode(1), '1') 45 | assert.deepStrictEqual(PathReporter.report(T.decode('str')), ['Invalid value "str" supplied to : number']) 46 | ``` 47 | 48 | Added in v0.5.12 49 | -------------------------------------------------------------------------------- /src/NonEmptyString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.5 3 | */ 4 | import * as t from 'io-ts' 5 | 6 | /** 7 | * @since 0.4.5 8 | */ 9 | export interface NonEmptyStringBrand { 10 | readonly NonEmptyString: unique symbol 11 | } 12 | 13 | /** 14 | * @since 0.4.5 15 | */ 16 | export type NonEmptyString = t.Branded 17 | 18 | /** 19 | * @since 0.4.5 20 | */ 21 | export interface NonEmptyStringC extends t.Type {} 22 | 23 | /** 24 | * A codec that succeeds if a string is not empty 25 | * 26 | * @example 27 | * import { NonEmptyString } from 'io-ts-types/lib/NonEmptyString' 28 | * import { right } from 'fp-ts/lib/Either' 29 | * import { PathReporter } from 'io-ts/lib/PathReporter' 30 | * 31 | * assert.deepStrictEqual(NonEmptyString.decode('a'), right('a')) 32 | * assert.deepStrictEqual(PathReporter.report(NonEmptyString.decode('')), ['Invalid value "" supplied to : NonEmptyString']) 33 | * 34 | * @since 0.4.5 35 | */ 36 | export const NonEmptyString: NonEmptyStringC = t.brand( 37 | t.string, 38 | (s): s is NonEmptyString => s.length > 0, 39 | 'NonEmptyString' 40 | ) 41 | -------------------------------------------------------------------------------- /src/mapOutput.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.3.2 3 | */ 4 | import * as t from 'io-ts' 5 | 6 | /** 7 | * Changes the output type of the given runtime type 8 | * 9 | * @example 10 | * import * as t from 'io-ts' 11 | * import { mapOutput } from 'io-ts-types/lib/mapOutput' 12 | * import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable' 13 | * import { none, some } from 'fp-ts/lib/Option' 14 | * 15 | * // Input: t.Type, number | null, t.mixed> 16 | * const Input = optionFromNullable(t.number) 17 | * 18 | * const toUndefined =
(x: A | null): A | undefined => (x === null ? undefined : x) 19 | * 20 | * // Output: t.Type, number | undefined, t.mixed> 21 | * const Output = mapOutput(Input, toUndefined) 22 | * 23 | * assert.strictEqual(Output.encode(none), undefined) 24 | * assert.strictEqual(Output.encode(some(1)), 1) 25 | * 26 | * @since 0.3.2 27 | */ 28 | export function mapOutput( 29 | codec: t.Type, 30 | f: (p: O) => P, 31 | name: string = codec.name 32 | ): t.Type { 33 | return new t.Type(name, codec.is, codec.validate, a => f(codec.encode(a))) 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Giulio Canti 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/fromNewtype.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import * as t from 'io-ts' 3 | import { fromNewtype } from '../src' 4 | import { assertFailure, assertSuccess } from './helpers' 5 | import { Newtype, iso } from 'newtype-ts' 6 | 7 | it('fromNewtype', () => { 8 | interface Token extends Newtype<{ readonly Token: unique symbol }, string> {} 9 | const T = fromNewtype(t.string) 10 | const token = iso().wrap('sometoken') 11 | assertSuccess(T.decode('sometoken'), token) 12 | assertFailure(T, 42, ['Invalid value 42 supplied to : fromNewtype(string)']) 13 | assert.ok(T.is('sometoken')) 14 | assert.deepStrictEqual(T.encode(token), 'sometoken') 15 | 16 | const T2 = fromNewtype(t.string, 'T2') 17 | assert.strictEqual(T2.name, 'T2') 18 | 19 | interface Id extends Newtype<{ readonly Id: unique symbol }, t.Int> {} 20 | const T3 = fromNewtype(t.Int) 21 | const id = iso().wrap(123 as any) 22 | assertSuccess(T3.decode(123), id) 23 | assertFailure(T3, 'test', ['Invalid value "test" supplied to : fromNewtype(Int)']) 24 | assert.ok(T3.is(123)) 25 | assert.deepStrictEqual(T3.encode(id), 123) 26 | }) 27 | -------------------------------------------------------------------------------- /src/nonEmptyArray.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { NonEmptyArray, fromArray, map } from 'fp-ts/lib/NonEmptyArray' 6 | import { isNonEmpty } from 'fp-ts/lib/Array' 7 | import { pipe } from 'fp-ts/lib/pipeable' 8 | import { chain } from 'fp-ts/lib/Either' 9 | import { isNone } from 'fp-ts/lib/Option' 10 | 11 | /** 12 | * @since 0.5.0 13 | */ 14 | export interface NonEmptyArrayC 15 | extends t.Type>, NonEmptyArray>, unknown> {} 16 | 17 | /** 18 | * @since 0.5.0 19 | */ 20 | export function nonEmptyArray( 21 | codec: C, 22 | name: string = `NonEmptyArray<${codec.name}>` 23 | ): NonEmptyArrayC { 24 | const arr = t.array(codec) 25 | return new t.Type( 26 | name, 27 | (u): u is NonEmptyArray> => arr.is(u) && isNonEmpty(u), 28 | (u, c) => 29 | pipe( 30 | arr.validate(u, c), 31 | chain(as => { 32 | const onea = fromArray(as) 33 | return isNone(onea) ? t.failure(u, c) : t.success(onea.value) 34 | }) 35 | ), 36 | map(codec.encode) 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /test/NonEmptyString.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { NonEmptyString } from '../src' 3 | import { assertSuccess, assertFailure } from './helpers' 4 | 5 | describe('NonEmptyString', () => { 6 | describe('is', () => { 7 | it('should check a isomorphic value', () => { 8 | const T = NonEmptyString 9 | assert.strictEqual(T.is(''), false) 10 | assert.strictEqual(T.is('a'), true) 11 | }) 12 | }) 13 | 14 | describe('decode', () => { 15 | it('should succeed validating a valid value', () => { 16 | const T = NonEmptyString 17 | assertSuccess(T.decode('a'), 'a' as NonEmptyString) 18 | }) 19 | 20 | it('should fail validation an invalid value', () => { 21 | const T = NonEmptyString 22 | assertFailure(T, null, ['Invalid value null supplied to : NonEmptyString']) 23 | assertFailure(T, '', ['Invalid value "" supplied to : NonEmptyString']) 24 | }) 25 | }) 26 | 27 | describe('encode', () => { 28 | it('should encode a isomorphic value', () => { 29 | const T = NonEmptyString 30 | assert.strictEqual(T.encode('a' as NonEmptyString), 'a') 31 | }) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /src/setFromArray.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import { Ord } from 'fp-ts/lib/Ord' 5 | import { every, fromArray, toArray } from 'fp-ts/lib/Set' 6 | import * as t from 'io-ts' 7 | import { pipe } from 'fp-ts/lib/pipeable' 8 | import { chain } from 'fp-ts/lib/Either' 9 | 10 | /** 11 | * @since 0.5.0 12 | */ 13 | export interface SetFromArrayC extends t.Type>, Array>, unknown> {} 14 | 15 | /** 16 | * @since 0.5.0 17 | */ 18 | export function setFromArray( 19 | codec: C, 20 | O: Ord>, 21 | name: string = `Set<${codec.name}>` 22 | ): SetFromArrayC { 23 | const arr = t.array(codec) 24 | const toArrayO = toArray(O) 25 | const fromArrayO = fromArray(O) 26 | return new t.Type( 27 | name, 28 | (u): u is Set> => u instanceof Set && every(codec.is)(u), 29 | (u, c) => 30 | pipe( 31 | arr.validate(u, c), 32 | chain(as => { 33 | const set = fromArrayO(as) 34 | return set.size !== as.length ? t.failure(u, c) : t.success(set) 35 | }) 36 | ), 37 | set => arr.encode(toArrayO(set)) 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /test/DateFromUnixTime.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { DateFromUnixTime } from '../src' 3 | import { assertSuccess, assertFailure } from './helpers' 4 | import { either } from 'fp-ts/lib/Either' 5 | 6 | const d = new Date(1973, 10, 30, 12, 12, 12, 12) 7 | const seconds = Math.floor(d.getTime() / 1000) 8 | 9 | describe('DateFromUnixTime', () => { 10 | it('is', () => { 11 | const T = DateFromUnixTime 12 | assert.strictEqual(T.is(d), true) 13 | assert.strictEqual(T.is(0), false) 14 | }) 15 | 16 | it('decode', () => { 17 | const T = DateFromUnixTime 18 | assertSuccess(T.decode(seconds), new Date(seconds * 1000)) 19 | assertSuccess(either.map(T.decode(seconds), d => d.getTime()), seconds * 1000) 20 | assertFailure(T, NaN, ['Invalid value NaN supplied to : DateFromUnixTime']) 21 | assertFailure(T, '', ['Invalid value "" supplied to : DateFromUnixTime']) 22 | assertFailure(T, 1.2345678901234568e79, ['Invalid value 1.2345678901234568e+79 supplied to : DateFromUnixTime']) 23 | }) 24 | 25 | it('encode', () => { 26 | const T = DateFromUnixTime 27 | assert.strictEqual(T.encode(d), seconds) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /src/BooleanFromNumber.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.13 3 | */ 4 | import * as t from 'io-ts' 5 | import { pipe } from 'fp-ts/lib/pipeable' 6 | import { map } from 'fp-ts/Either' 7 | 8 | /** 9 | * @since 0.5.13 10 | */ 11 | export interface BooleanFromNumberC extends t.Type {} 12 | 13 | /** 14 | * @example 15 | * import { BooleanFromNumber } from 'io-ts-types/lib/BooleanFromNumber' 16 | * import { right } from 'fp-ts/lib/Either' 17 | * import { PathReporter } from 'io-ts/lib/PathReporter' 18 | * 19 | * assert.deepStrictEqual(BooleanFromNumber.decode(1), right(true)) 20 | * assert.deepStrictEqual(BooleanFromNumber.decode(0), right(false)) 21 | * assert.deepStrictEqual(BooleanFromNumber.decode(123), right(true)) 22 | * assert.deepStrictEqual(PathReporter.report(BooleanFromNumber.decode('a')), ['Invalid value "a" supplied to : BooleanFromNumber']) 23 | * 24 | * @since 0.5.13 25 | */ 26 | export const BooleanFromNumber: BooleanFromNumberC = new t.Type( 27 | 'BooleanFromNumber', 28 | t.boolean.is, 29 | (u, c) => 30 | pipe( 31 | t.number.validate(u, c), 32 | map(n => n !== 0) 33 | ), 34 | Number 35 | ) 36 | -------------------------------------------------------------------------------- /src/IntFromString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.4.4 3 | */ 4 | import * as t from 'io-ts' 5 | import { NumberFromString } from './NumberFromString' 6 | import { pipe } from 'fp-ts/lib/pipeable' 7 | import { chain } from 'fp-ts/lib/Either' 8 | 9 | /** 10 | * @since 0.4.4 11 | */ 12 | export interface IntFromStringC extends t.Type {} 13 | 14 | /** 15 | * A codec that succeeds if a string can be parsed to an integer 16 | * 17 | * @example 18 | * import { IntFromString } from 'io-ts-types/lib/IntFromString' 19 | * import { right } from 'fp-ts/lib/Either' 20 | * import { PathReporter } from 'io-ts/lib/PathReporter' 21 | * 22 | * assert.deepStrictEqual(IntFromString.decode('1'), right(1)) 23 | * assert.deepStrictEqual(PathReporter.report(IntFromString.decode('1.1')), ['Invalid value "1.1" supplied to : IntFromString']) 24 | * 25 | * @since 0.4.4 26 | */ 27 | export const IntFromString: IntFromStringC = new t.Type( 28 | 'IntFromString', 29 | t.Int.is, 30 | (u, c) => 31 | pipe( 32 | NumberFromString.validate(u, c), 33 | chain(n => (t.Int.is(n) ? t.success(n) : t.failure(u, c))) 34 | ), 35 | NumberFromString.encode 36 | ) 37 | -------------------------------------------------------------------------------- /docs/modules/fromNullable.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: fromNullable.ts 3 | nav_order: 11 4 | parent: Modules 5 | --- 6 | 7 | # fromNullable overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [fromNullable](#fromnullable) 16 | 17 | --- 18 | 19 | # fromNullable 20 | 21 | Returns a clone of the given codec that replace a nullable input with the given value `a` 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function fromNullable(codec: C, a: t.TypeOf, name = `fromNullable(${codec.name})`): C { ... } 27 | ``` 28 | 29 | **Example** 30 | 31 | ```ts 32 | import { fromNullable } from 'io-ts-types/lib/fromNullable' 33 | import * as t from 'io-ts' 34 | import { right } from 'fp-ts/lib/Either' 35 | import { PathReporter } from 'io-ts/lib/PathReporter' 36 | 37 | const T = fromNullable(t.number, -1) 38 | 39 | assert.deepStrictEqual(T.decode(1), right(1)) 40 | assert.deepStrictEqual(T.decode(null), right(-1)) 41 | assert.deepStrictEqual(T.decode(undefined), right(-1)) 42 | assert.deepStrictEqual(PathReporter.report(T.decode('a')), ['Invalid value "a" supplied to : fromNullable(number)']) 43 | ``` 44 | 45 | Added in v0.5.0 46 | -------------------------------------------------------------------------------- /src/BooleanFromString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { pipe } from 'fp-ts/lib/pipeable' 6 | import { chain } from 'fp-ts/lib/Either' 7 | 8 | /** 9 | * @since 0.5.0 10 | */ 11 | export interface BooleanFromStringC extends t.Type {} 12 | 13 | /** 14 | * @example 15 | * import { BooleanFromString } from 'io-ts-types/lib/BooleanFromString' 16 | * import { right } from 'fp-ts/lib/Either' 17 | * import { PathReporter } from 'io-ts/lib/PathReporter' 18 | * 19 | * assert.deepStrictEqual(BooleanFromString.decode('true'), right(true)) 20 | * assert.deepStrictEqual(BooleanFromString.decode('false'), right(false)) 21 | * assert.deepStrictEqual(PathReporter.report(BooleanFromString.decode('a')), ['Invalid value "a" supplied to : BooleanFromString']) 22 | * 23 | * @since 0.5.0 24 | */ 25 | export const BooleanFromString: BooleanFromStringC = new t.Type( 26 | 'BooleanFromString', 27 | t.boolean.is, 28 | (u, c) => 29 | pipe( 30 | t.string.validate(u, c), 31 | chain(s => (s === 'true' ? t.success(true) : s === 'false' ? t.success(false) : t.failure(u, c))) 32 | ), 33 | String 34 | ) 35 | -------------------------------------------------------------------------------- /test/withFallback.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import * as t from 'io-ts' 3 | import { withFallback } from '../src' 4 | import { assertSuccess } from './helpers' 5 | 6 | describe('withFallback', () => { 7 | const zero: t.Int = 0 as any 8 | const one: t.Int = 1 as any 9 | 10 | describe('name', () => { 11 | it('should assign a default name', () => { 12 | const T = withFallback(t.Int, zero) 13 | assert.strictEqual(T.name, 'withFallback(Int)') 14 | }) 15 | 16 | it('should accept a name', () => { 17 | const T = withFallback(t.Int, zero, 'T') 18 | assert.strictEqual(T.name, 'T') 19 | }) 20 | }) 21 | 22 | describe('is', () => { 23 | it('should check a isomorphic value', () => { 24 | const T = withFallback(t.Int, zero) 25 | assert.strictEqual(T.is(1), true) 26 | assert.strictEqual(T.is(1.1), false) 27 | assert.strictEqual(T.is('a'), false) 28 | }) 29 | }) 30 | 31 | describe('decode', () => { 32 | it('should decode a isomorphic value', () => { 33 | const T = withFallback(t.Int, zero) 34 | assertSuccess(T.decode(1), one) 35 | assertSuccess(T.decode(1.2), zero) 36 | }) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /docs/modules/IntFromString.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: IntFromString.ts 3 | nav_order: 15 4 | parent: Modules 5 | --- 6 | 7 | # IntFromString overview 8 | 9 | Added in v0.4.4 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [IntFromStringC (interface)](#intfromstringc-interface) 16 | - [IntFromString](#intfromstring) 17 | 18 | --- 19 | 20 | # IntFromStringC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface IntFromStringC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.4.4 29 | 30 | # IntFromString 31 | 32 | A codec that succeeds if a string can be parsed to an integer 33 | 34 | **Signature** 35 | 36 | ```ts 37 | export const IntFromString: IntFromStringC = ... 38 | ``` 39 | 40 | **Example** 41 | 42 | ```ts 43 | import { IntFromString } from 'io-ts-types/lib/IntFromString' 44 | import { right } from 'fp-ts/lib/Either' 45 | import { PathReporter } from 'io-ts/lib/PathReporter' 46 | 47 | assert.deepStrictEqual(IntFromString.decode('1'), right(1)) 48 | assert.deepStrictEqual(PathReporter.report(IntFromString.decode('1.1')), [ 49 | 'Invalid value "1.1" supplied to : IntFromString' 50 | ]) 51 | ``` 52 | 53 | Added in v0.4.4 54 | -------------------------------------------------------------------------------- /scripts/FileSystem.ts: -------------------------------------------------------------------------------- 1 | import * as TE from 'fp-ts/TaskEither' 2 | import { flow } from 'fp-ts/function' 3 | import * as fs from 'fs' 4 | import G from 'glob' 5 | 6 | export interface FileSystem { 7 | readonly readFile: (path: string) => TE.TaskEither 8 | readonly writeFile: (path: string, content: string) => TE.TaskEither 9 | readonly copyFile: (from: string, to: string) => TE.TaskEither 10 | readonly glob: (pattern: string) => TE.TaskEither> 11 | readonly mkdir: (path: string) => TE.TaskEither 12 | } 13 | 14 | const readFile = TE.taskify(fs.readFile) 15 | const writeFile = TE.taskify(fs.writeFile) 16 | const copyFile = TE.taskify(fs.copyFile) 17 | const glob = TE.taskify>(G) 18 | const mkdirTE = TE.taskify(fs.mkdir) 19 | 20 | export const fileSystem: FileSystem = { 21 | readFile: (path) => readFile(path, 'utf8'), 22 | writeFile, 23 | copyFile, 24 | glob, 25 | mkdir: flow( 26 | mkdirTE, 27 | TE.map(() => undefined) 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /docs/modules/fromNewtype.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: fromNewtype.ts 3 | nav_order: 10 4 | parent: Modules 5 | --- 6 | 7 | # fromNewtype overview 8 | 9 | Added in v0.5.2 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [fromNewtype](#fromnewtype) 16 | 17 | --- 18 | 19 | # fromNewtype 20 | 21 | Returns a codec from a newtype 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function fromNewtype( 27 | codec: t.Type, t.OutputOf>>, 28 | name = `fromNewtype(${codec.name})` 29 | ): t.Type, unknown> { ... } 30 | ``` 31 | 32 | **Example** 33 | 34 | ```ts 35 | import { fromNewtype } from 'io-ts-types/lib/fromNewtype' 36 | import * as t from 'io-ts' 37 | import { right } from 'fp-ts/lib/Either' 38 | import { PathReporter } from 'io-ts/lib/PathReporter' 39 | import { Newtype, iso } from 'newtype-ts' 40 | 41 | interface Token extends Newtype<{ readonly Token: unique symbol }, string> {} 42 | 43 | const T = fromNewtype(t.string) 44 | 45 | assert.deepStrictEqual(T.decode('sometoken'), right(iso().wrap('sometoken'))) 46 | assert.deepStrictEqual(PathReporter.report(T.decode(42)), ['Invalid value 42 supplied to : fromNewtype(string)']) 47 | ``` 48 | 49 | Added in v0.5.2 50 | -------------------------------------------------------------------------------- /test/either.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { left, right } from 'fp-ts/lib/Either' 3 | import * as t from 'io-ts' 4 | import { either } from '../src' 5 | import { assertFailure, assertSuccess } from './helpers' 6 | 7 | describe('either', () => { 8 | it('name', () => { 9 | const T = either(t.string, t.number, 'T') 10 | assert.strictEqual(T.name, 'T') 11 | }) 12 | 13 | it('is', () => { 14 | const T = either(t.string, t.number) 15 | assert.strictEqual(T.is(right(1)), true) 16 | assert.strictEqual(T.is(right('foo')), false) 17 | assert.strictEqual(T.is(left(1)), false) 18 | assert.strictEqual(T.is(left('foo')), true) 19 | }) 20 | 21 | it('decode', () => { 22 | const T = either(t.string, t.number) 23 | assertSuccess(T.decode({ _tag: 'Left', left: 's' }), left('s')) 24 | assertSuccess(T.decode({ _tag: 'Right', right: 1 }), right(1)) 25 | assertFailure(T, null, ['Invalid value null supplied to : Either']) 26 | }) 27 | 28 | it('encode', () => { 29 | const T = either(t.string, t.number) 30 | assert.deepStrictEqual(T.encode(left('a')), { _tag: 'Left', left: 'a' }) 31 | assert.deepStrictEqual(T.encode(right(1)), { _tag: 'Right', right: 1 }) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /test/readonlyMapFromEntries.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { pipe } from 'fp-ts/function' 3 | import { Ord, ordString, contramap } from 'fp-ts/Ord' 4 | import * as t from 'io-ts' 5 | import { assertSuccess, assertFailure } from './helpers' 6 | 7 | import { readonlyMapFromEntries } from '../src/readonlyMapFromEntries' 8 | 9 | describe('readonlyMapFromEntries', () => { 10 | const K = t.type({ a: t.string }) 11 | const KO: Ord> = pipe( 12 | ordString, 13 | contramap(m => m.a) 14 | ) 15 | const C = t.type({ b: t.number }) 16 | const T = readonlyMapFromEntries(K, KO, C) 17 | 18 | it('name', () => { 19 | const T = readonlyMapFromEntries(K, KO, C, 'T') 20 | assert.strictEqual(T.name, 'T') 21 | }) 22 | 23 | it('decode', () => { 24 | assertSuccess(T.decode([]), new Map()) 25 | assertSuccess( 26 | T.decode([[{ a: '1' }, { b: 1 }], [{ a: '2' }, { b: 2 }]]), 27 | new Map([[{ a: '1' }, { b: 1 }], [{ a: '2' }, { b: 2 }]]) 28 | ) 29 | assertFailure( 30 | T, 31 | [[{ a: '1' }, { b: 1 }], [{ a: '1' }, { b: 2 }]], 32 | [ 33 | 'Invalid value [[{"a":"1"},{"b":1}],[{"a":"1"},{"b":2}]] supplied to : ReadonlyMap<{ a: string }, { b: number }>' 34 | ] 35 | ) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /docs/modules/BooleanFromString.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: BooleanFromString.ts 3 | nav_order: 3 4 | parent: Modules 5 | --- 6 | 7 | # BooleanFromString overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [BooleanFromStringC (interface)](#booleanfromstringc-interface) 16 | - [BooleanFromString](#booleanfromstring) 17 | 18 | --- 19 | 20 | # BooleanFromStringC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface BooleanFromStringC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.0 29 | 30 | # BooleanFromString 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const BooleanFromString: BooleanFromStringC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { BooleanFromString } from 'io-ts-types/lib/BooleanFromString' 42 | import { right } from 'fp-ts/lib/Either' 43 | import { PathReporter } from 'io-ts/lib/PathReporter' 44 | 45 | assert.deepStrictEqual(BooleanFromString.decode('true'), right(true)) 46 | assert.deepStrictEqual(BooleanFromString.decode('false'), right(false)) 47 | assert.deepStrictEqual(PathReporter.report(BooleanFromString.decode('a')), [ 48 | 'Invalid value "a" supplied to : BooleanFromString' 49 | ]) 50 | ``` 51 | 52 | Added in v0.5.0 53 | -------------------------------------------------------------------------------- /test/BigIntFromString.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { BigIntFromString } from '../src' 3 | import { assertSuccess, assertFailure } from './helpers' 4 | 5 | describe('BigIntFromString', () => { 6 | it('is', () => { 7 | const T = BigIntFromString 8 | assert.strictEqual(T.is(BigInt(5)), true) 9 | assert.strictEqual(T.is(null), false) 10 | }) 11 | it('decode', () => { 12 | const T = BigIntFromString 13 | assertSuccess(T.decode('0'), BigInt(0)) 14 | assertSuccess(T.decode('10'), BigInt(10)) 15 | assertSuccess(T.decode('-1'), BigInt(-1)) 16 | assertSuccess(T.decode('11'), BigInt(11)) 17 | assertFailure(T, '5.5', ['Invalid value "5.5" supplied to : BigIntFromString']) 18 | assertFailure(T, '-5.5', ['Invalid value "-5.5" supplied to : BigIntFromString']) 19 | assertFailure(T, '', ['Invalid value "" supplied to : BigIntFromString']) 20 | assertFailure(T, ' ', ['Invalid value " " supplied to : BigIntFromString']) 21 | assertFailure(T, 'a', ['Invalid value "a" supplied to : BigIntFromString']) 22 | assertFailure(T, 'a5', ['Invalid value "a5" supplied to : BigIntFromString']) 23 | }) 24 | it('encode', () => { 25 | const T = BigIntFromString 26 | assert.strictEqual(T.encode(BigInt(5)), '5') 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /docs/modules/readonlyNonEmptyArray.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: readonlyNonEmptyArray.ts 3 | nav_order: 25 4 | parent: Modules 5 | --- 6 | 7 | # readonlyNonEmptyArray overview 8 | 9 | Added in v0.5.7 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [ReadonlyNonEmptyArray (interface)](#readonlynonemptyarray-interface) 16 | - [ReadonlyNonEmptyArrayC (interface)](#readonlynonemptyarrayc-interface) 17 | - [readonlyNonEmptyArray](#readonlynonemptyarray) 18 | 19 | --- 20 | 21 | # ReadonlyNonEmptyArray (interface) 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export interface ReadonlyNonEmptyArray
extends ReadonlyArray { 27 | readonly 0: A 28 | } 29 | ``` 30 | 31 | Added in v0.5.7 32 | 33 | # ReadonlyNonEmptyArrayC (interface) 34 | 35 | **Signature** 36 | 37 | ```ts 38 | export interface ReadonlyNonEmptyArrayC 39 | extends t.Type>, ReadonlyNonEmptyArray>, unknown> {} 40 | ``` 41 | 42 | Added in v0.5.7 43 | 44 | # readonlyNonEmptyArray 45 | 46 | **Signature** 47 | 48 | ```ts 49 | export function readonlyNonEmptyArray( 50 | codec: C, 51 | name: string = `ReadonlyNonEmptyArray<${codec.name}>` 52 | ): ReadonlyNonEmptyArrayC { ... } 53 | ``` 54 | 55 | Added in v0.5.7 56 | -------------------------------------------------------------------------------- /src/JsonFromString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.14 3 | */ 4 | import * as t from 'io-ts' 5 | 6 | /** 7 | * Copied from `fp-ts/Either` module. 8 | * 9 | * @since 0.5.14 10 | */ 11 | export type Json = boolean | number | string | null | JsonArray | JsonRecord 12 | 13 | /** 14 | * @since 0.5.14 15 | */ 16 | export interface JsonRecord { 17 | readonly [key: string]: Json 18 | } 19 | 20 | /** 21 | * @since 0.5.14 22 | */ 23 | export interface JsonArray extends ReadonlyArray {} 24 | 25 | /** 26 | * @since 0.5.15 27 | */ 28 | export const JsonArray: t.Type = t.recursion('JsonArray', () => t.readonlyArray(Json)) 29 | 30 | /** 31 | * @since 0.5.15 32 | */ 33 | export const JsonRecord: t.Type = t.recursion('JsonRecord', () => t.record(t.string, Json)) 34 | 35 | /** 36 | * @since 0.5.15 37 | */ 38 | export const Json: t.Type = t.union([t.boolean, t.number, t.string, t.null, JsonArray, JsonRecord], 'Json') 39 | 40 | /** 41 | * @since 0.5.14 42 | */ 43 | export const JsonFromString = new t.Type( 44 | 'JsonFromString', 45 | Json.is, 46 | (s, c) => { 47 | try { 48 | return t.success(JSON.parse(s)) 49 | } catch (e) { 50 | return t.failure(s, c) 51 | } 52 | }, 53 | json => JSON.stringify(json) 54 | ) 55 | -------------------------------------------------------------------------------- /docs/modules/mapOutput.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: mapOutput.ts 3 | nav_order: 18 4 | parent: Modules 5 | --- 6 | 7 | # mapOutput overview 8 | 9 | Added in v0.3.2 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [mapOutput](#mapoutput) 16 | 17 | --- 18 | 19 | # mapOutput 20 | 21 | Changes the output type of the given runtime type 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export function mapOutput( 27 | codec: t.Type, 28 | f: (p: O) => P, 29 | name: string = codec.name 30 | ): t.Type { ... } 31 | ``` 32 | 33 | **Example** 34 | 35 | ```ts 36 | import * as t from 'io-ts' 37 | import { mapOutput } from 'io-ts-types/lib/mapOutput' 38 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable' 39 | import { none, some } from 'fp-ts/lib/Option' 40 | 41 | // Input: t.Type, number | null, t.mixed> 42 | const Input = optionFromNullable(t.number) 43 | 44 | const toUndefined =
(x: A | null): A | undefined => (x === null ? undefined : x) 45 | 46 | // Output: t.Type, number | undefined, t.mixed> 47 | const Output = mapOutput(Input, toUndefined) 48 | 49 | assert.strictEqual(Output.encode(none), undefined) 50 | assert.strictEqual(Output.encode(some(1)), 1) 51 | ``` 52 | 53 | Added in v0.3.2 54 | -------------------------------------------------------------------------------- /src/getLenses.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import * as t from 'io-ts' 5 | import { Lens } from 'monocle-ts' 6 | 7 | /** 8 | * @since 0.5.0 9 | */ 10 | export interface ExactHasLenses extends t.ExactType {} 11 | 12 | /** 13 | * @since 0.5.0 14 | */ 15 | export type HasLenses = t.InterfaceType | ExactHasLenses 16 | 17 | function getProps(codec: HasLenses): t.Props { 18 | switch (codec._tag) { 19 | case 'InterfaceType': 20 | return codec.props 21 | case 'ExactType': 22 | return getProps(codec.type) 23 | } 24 | } 25 | 26 | const fromProp = Lens.fromProp() 27 | 28 | /** 29 | * Return a `Lens` for each prop 30 | * 31 | * @example 32 | * import * as t from 'io-ts' 33 | * import { getLenses } from 'io-ts-types/lib/getLenses' 34 | * 35 | * const Person = t.type({ 36 | * name: t.string, 37 | * age: t.number 38 | * }) 39 | * 40 | * const lenses = getLenses(Person) 41 | * assert.strictEqual(lenses.age.get({ name: 'Giulio', age: 44 }), 44) 42 | * 43 | * @since 0.5.0 44 | */ 45 | export function getLenses( 46 | codec: C 47 | ): { [K in keyof t.TypeOf]: Lens, t.TypeOf[K]> } { 48 | const r: any = {} 49 | for (const k in getProps(codec)) { 50 | r[k] = fromProp(k) 51 | } 52 | return r 53 | } 54 | -------------------------------------------------------------------------------- /docs/modules/UUID.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: UUID.ts 3 | nav_order: 29 4 | parent: Modules 5 | --- 6 | 7 | # UUID overview 8 | 9 | Added in v0.4.6 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [UUIDBrand (interface)](#uuidbrand-interface) 16 | - [UUID (type alias)](#uuid-type-alias) 17 | - [UUID](#uuid) 18 | 19 | --- 20 | 21 | # UUIDBrand (interface) 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export interface UUIDBrand { 27 | readonly UUID: unique symbol 28 | } 29 | ``` 30 | 31 | Added in v0.4.6 32 | 33 | # UUID (type alias) 34 | 35 | **Signature** 36 | 37 | ```ts 38 | export type UUID = t.Branded 39 | ``` 40 | 41 | Added in v0.4.6 42 | 43 | # UUID 44 | 45 | **Signature** 46 | 47 | ```ts 48 | export const UUID: t.BrandC = ... 49 | ``` 50 | 51 | **Example** 52 | 53 | ```ts 54 | import { UUID } from 'io-ts-types/lib/UUID' 55 | import { right } from 'fp-ts/lib/Either' 56 | import { PathReporter } from 'io-ts/lib/PathReporter' 57 | 58 | assert.deepStrictEqual( 59 | UUID.decode('00000000-0000-0000-0000-000000000000'), 60 | right('00000000-0000-0000-0000-000000000000') 61 | ) 62 | assert.deepStrictEqual(PathReporter.report(UUID.decode('not a uuid')), [ 63 | 'Invalid value "not a uuid" supplied to : UUID' 64 | ]) 65 | ``` 66 | 67 | Added in v0.4.6 68 | -------------------------------------------------------------------------------- /docs/modules/BooleanFromNumber.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: BooleanFromNumber.ts 3 | nav_order: 2 4 | parent: Modules 5 | --- 6 | 7 | # BooleanFromNumber overview 8 | 9 | Added in v0.5.13 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [BooleanFromNumberC (interface)](#booleanfromnumberc-interface) 16 | - [BooleanFromNumber](#booleanfromnumber) 17 | 18 | --- 19 | 20 | # BooleanFromNumberC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface BooleanFromNumberC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.13 29 | 30 | # BooleanFromNumber 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const BooleanFromNumber: BooleanFromNumberC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { BooleanFromNumber } from 'io-ts-types/lib/BooleanFromNumber' 42 | import { right } from 'fp-ts/lib/Either' 43 | import { PathReporter } from 'io-ts/lib/PathReporter' 44 | 45 | assert.deepStrictEqual(BooleanFromNumber.decode(1), right(true)) 46 | assert.deepStrictEqual(BooleanFromNumber.decode(0), right(false)) 47 | assert.deepStrictEqual(BooleanFromNumber.decode(123), right(true)) 48 | assert.deepStrictEqual(PathReporter.report(BooleanFromNumber.decode('a')), [ 49 | 'Invalid value "a" supplied to : BooleanFromNumber' 50 | ]) 51 | ``` 52 | 53 | Added in v0.5.13 54 | -------------------------------------------------------------------------------- /test/nonEmptyArray.ts: -------------------------------------------------------------------------------- 1 | import { nonEmptyArray, NumberFromString } from '../src' 2 | import * as t from 'io-ts' 3 | import { cons } from 'fp-ts/lib/NonEmptyArray' 4 | import * as assert from 'assert' 5 | import { assertFailure, assertSuccess } from './helpers' 6 | 7 | describe('nonEmptyArray', () => { 8 | it('name', () => { 9 | const T = nonEmptyArray(t.number, 'T') 10 | assert.strictEqual(T.name, 'T') 11 | }) 12 | 13 | it('is', () => { 14 | const T = nonEmptyArray(t.number) 15 | assert.strictEqual(T.is(cons(1, [2, 3])), true) 16 | assert.strictEqual(T.is(null), false) 17 | assert.strictEqual(T.is(cons('a', ['b', 'c'])), false) 18 | }) 19 | 20 | it('decode', () => { 21 | const T = nonEmptyArray(t.number) 22 | assertSuccess(T.decode([1]), cons(1, [])) 23 | assertSuccess(T.decode([1, 2, 3]), cons(1, [2, 3])) 24 | assertFailure(T, null, ['Invalid value null supplied to : NonEmptyArray']) 25 | assertFailure(T, [], ['Invalid value [] supplied to : NonEmptyArray']) 26 | }) 27 | 28 | it('encode', () => { 29 | const T = nonEmptyArray(t.number) 30 | assert.deepStrictEqual(T.encode(cons(1, [2, 3])), [1, 2, 3]) 31 | assert.deepStrictEqual(T.encode(cons(1, [])), [1]) 32 | const T2 = nonEmptyArray(NumberFromString) 33 | assert.deepStrictEqual(T2.encode(cons(1, [])), ['1']) 34 | }) 35 | }) 36 | -------------------------------------------------------------------------------- /docs/modules/getLenses.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: getLenses.ts 3 | nav_order: 13 4 | parent: Modules 5 | --- 6 | 7 | # getLenses overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [ExactHasLenses (interface)](#exacthaslenses-interface) 16 | - [HasLenses (type alias)](#haslenses-type-alias) 17 | - [getLenses](#getlenses) 18 | 19 | --- 20 | 21 | # ExactHasLenses (interface) 22 | 23 | **Signature** 24 | 25 | ```ts 26 | export interface ExactHasLenses extends t.ExactType {} 27 | ``` 28 | 29 | Added in v0.5.0 30 | 31 | # HasLenses (type alias) 32 | 33 | **Signature** 34 | 35 | ```ts 36 | export type HasLenses = t.InterfaceType | ExactHasLenses 37 | ``` 38 | 39 | Added in v0.5.0 40 | 41 | # getLenses 42 | 43 | Return a `Lens` for each prop 44 | 45 | **Signature** 46 | 47 | ```ts 48 | export function getLenses( 49 | codec: C 50 | ): { [K in keyof t.TypeOf]: Lens, t.TypeOf[K]> } { ... } 51 | ``` 52 | 53 | **Example** 54 | 55 | ```ts 56 | import * as t from 'io-ts' 57 | import { getLenses } from 'io-ts-types/lib/getLenses' 58 | 59 | const Person = t.type({ 60 | name: t.string, 61 | age: t.number 62 | }) 63 | 64 | const lenses = getLenses(Person) 65 | assert.strictEqual(lenses.age.get({ name: 'Giulio', age: 44 }), 44) 66 | ``` 67 | 68 | Added in v0.5.0 69 | -------------------------------------------------------------------------------- /test/helpers.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import * as t from 'io-ts' 3 | import { PathReporter } from 'io-ts/lib/PathReporter' 4 | import { isRight, isLeft } from 'fp-ts/lib/Either' 5 | 6 | export function assertStrictEqual(result: t.Validation, expected: any): void { 7 | if (isRight(result)) { 8 | assert.deepStrictEqual(result.right, expected) 9 | } else { 10 | throw new Error(`${result} is not a right`) 11 | } 12 | } 13 | 14 | export function assertSuccess(result: t.Validation, expected?: T): void { 15 | if (isRight(result)) { 16 | if (expected !== undefined) { 17 | assert.deepStrictEqual(result.right, expected) 18 | } 19 | } else { 20 | throw new Error(`${result} is not a right`) 21 | } 22 | } 23 | 24 | export function assertStrictSuccess(result: t.Validation, expected: T): void { 25 | if (isRight(result)) { 26 | if (expected !== undefined) { 27 | assert.strictEqual(result.right, expected) 28 | } 29 | } else { 30 | throw new Error(`${result} is not a right`) 31 | } 32 | } 33 | 34 | export function assertFailure(codec: t.Any, value: unknown, errors: Array): void { 35 | const result = codec.decode(value) 36 | if (isLeft(result)) { 37 | assert.deepStrictEqual(PathReporter.report(result), errors) 38 | } else { 39 | throw new Error(`${result} is not a left`) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/fromNewtype.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.2 3 | */ 4 | import { AnyNewtype, CarrierOf, iso } from 'newtype-ts' 5 | import * as t from 'io-ts' 6 | import { pipe } from 'fp-ts/lib/pipeable' 7 | import { map } from 'fp-ts/lib/Either' 8 | 9 | /** 10 | * Returns a codec from a newtype 11 | * 12 | * @example 13 | * import { fromNewtype } from 'io-ts-types/lib/fromNewtype' 14 | * import * as t from 'io-ts' 15 | * import { right } from 'fp-ts/lib/Either' 16 | * import { PathReporter } from 'io-ts/lib/PathReporter' 17 | * import { Newtype, iso } from 'newtype-ts' 18 | * 19 | * interface Token extends Newtype<{ readonly Token: unique symbol }, string> {} 20 | * 21 | * const T = fromNewtype(t.string) 22 | * 23 | * assert.deepStrictEqual(T.decode('sometoken'), right(iso().wrap('sometoken'))) 24 | * assert.deepStrictEqual(PathReporter.report(T.decode(42)), ['Invalid value 42 supplied to : fromNewtype(string)']) 25 | * 26 | * @since 0.5.2 27 | */ 28 | export function fromNewtype( 29 | codec: t.Type, t.OutputOf>>, 30 | name = `fromNewtype(${codec.name})` 31 | ): t.Type, unknown> { 32 | const i = iso() 33 | return new t.Type( 34 | name, 35 | (u): u is N => codec.is(u), 36 | (u, c) => 37 | pipe( 38 | codec.validate(u, c), 39 | map(i.wrap) 40 | ), 41 | a => codec.encode(i.unwrap(a)) 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "\U0001F680Feature request" 3 | about: Suggest an idea for io-ts-types 4 | --- 5 | 6 | ## 🚀 Feature request 7 | 8 | ### Current Behavior 9 | 10 | 11 | 12 | ### Desired Behavior 13 | 14 | 15 | 16 | ### Suggested Solution 17 | 18 | 19 | 20 | 21 | 22 | ### Who does this impact? Who is this for? 23 | 24 | 25 | 26 | ### Describe alternatives you've considered 27 | 28 | 29 | 30 | ### Additional context 31 | 32 | 33 | 34 | ### Your environment 35 | 36 | 37 | 38 | | Software | Version(s) | 39 | | ----------- | ---------- | 40 | | fp-ts | | 41 | | io-ts | | 42 | | io-ts-types | | 43 | | TypeScript | | 44 | -------------------------------------------------------------------------------- /test/optionFromNullable.ts: -------------------------------------------------------------------------------- 1 | import { assertSuccess, assertFailure } from './helpers' 2 | import { optionFromNullable } from '../src' 3 | import * as t from 'io-ts' 4 | import * as assert from 'assert' 5 | import { NumberFromString } from '../src' 6 | import { none, some } from 'fp-ts/lib/Option' 7 | 8 | describe('optionFromNullable', () => { 9 | it('name', () => { 10 | const T = optionFromNullable(t.number, 'T') 11 | assert.strictEqual(T.name, 'T') 12 | }) 13 | 14 | it('is', () => { 15 | const T1 = optionFromNullable(t.number) 16 | assert.strictEqual(T1.is(some(1)), true) 17 | assert.strictEqual(T1.is(some('foo')), false) 18 | }) 19 | 20 | it('decode', () => { 21 | const T1 = optionFromNullable(t.number) 22 | assertSuccess(T1.decode(null), none) 23 | assertSuccess(T1.decode(undefined), none) 24 | assertSuccess(T1.decode(1), some(1)) 25 | assertFailure(T1, 'a', ['Invalid value "a" supplied to : Option']) 26 | 27 | const T2 = optionFromNullable(NumberFromString) 28 | assertSuccess(T2.decode(null), none) 29 | assertSuccess(T2.decode('1'), some(1)) 30 | }) 31 | 32 | it('encode', () => { 33 | const T1 = optionFromNullable(t.number) 34 | assert.strictEqual(T1.encode(some(1)), 1) 35 | assert.strictEqual(T1.encode(none), null) 36 | const T2 = optionFromNullable(NumberFromString) 37 | assert.strictEqual(T2.encode(none), null) 38 | assert.strictEqual(T2.encode(some(1)), '1') 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /docs/modules/BigIntFromString.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: BigIntFromString.ts 3 | nav_order: 1 4 | parent: Modules 5 | --- 6 | 7 | # BigIntFromString overview 8 | 9 | Added in v0.5.11 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [BigIntFromStringC (interface)](#bigintfromstringc-interface) 16 | - [BigIntFromString](#bigintfromstring) 17 | 18 | --- 19 | 20 | # BigIntFromStringC (interface) 21 | 22 | **Signature** 23 | 24 | ```ts 25 | export interface BigIntFromStringC extends t.Type {} 26 | ``` 27 | 28 | Added in v0.5.11 29 | 30 | # BigIntFromString 31 | 32 | **Signature** 33 | 34 | ```ts 35 | export const BigIntFromString: BigIntFromStringC = ... 36 | ``` 37 | 38 | **Example** 39 | 40 | ```ts 41 | import { BigIntFromString } from 'io-ts-types/lib/BigIntFromString' 42 | import { right } from 'fp-ts/lib/Either' 43 | import { PathReporter } from 'io-ts/lib/PathReporter' 44 | 45 | assert.deepStrictEqual(BigIntFromString.decode('1'), right(BigInt(1))) 46 | assert.deepStrictEqual(PathReporter.report(BigIntFromString.decode('1.1')), [ 47 | 'Invalid value "1.1" supplied to : BigIntFromString' 48 | ]) 49 | assert.deepStrictEqual(PathReporter.report(BigIntFromString.decode('')), [ 50 | 'Invalid value "" supplied to : BigIntFromString' 51 | ]) 52 | assert.deepStrictEqual(PathReporter.report(BigIntFromString.decode(' ')), [ 53 | 'Invalid value " " supplied to : BigIntFromString' 54 | ]) 55 | ``` 56 | 57 | Added in v0.5.11 58 | -------------------------------------------------------------------------------- /src/BigIntFromString.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.11 3 | */ 4 | import * as t from 'io-ts' 5 | import { pipe } from 'fp-ts/lib/pipeable' 6 | import { chain } from 'fp-ts/lib/Either' 7 | import { NonEmptyString } from './NonEmptyString' 8 | 9 | /** 10 | * @since 0.5.11 11 | */ 12 | export interface BigIntFromStringC extends t.Type {} 13 | 14 | /** 15 | * @example 16 | * import { BigIntFromString } from 'io-ts-types/lib/BigIntFromString' 17 | * import { right } from 'fp-ts/lib/Either' 18 | * import { PathReporter } from 'io-ts/lib/PathReporter' 19 | * 20 | * assert.deepStrictEqual(BigIntFromString.decode('1'), right(BigInt(1))) 21 | * assert.deepStrictEqual(PathReporter.report(BigIntFromString.decode('1.1')), ['Invalid value "1.1" supplied to : BigIntFromString']) 22 | * assert.deepStrictEqual(PathReporter.report(BigIntFromString.decode('')), ['Invalid value "" supplied to : BigIntFromString']) 23 | * assert.deepStrictEqual(PathReporter.report(BigIntFromString.decode(' ')), ['Invalid value " " supplied to : BigIntFromString']) 24 | * 25 | * @since 0.5.11 26 | */ 27 | export const BigIntFromString: BigIntFromStringC = new t.Type( 28 | 'BigIntFromString', 29 | // tslint:disable-next-line 30 | (u): u is bigint => typeof u === 'bigint', 31 | (u, c) => 32 | pipe( 33 | t.string.validate(u, c), 34 | chain(s => { 35 | if (!NonEmptyString.is(s.trim())) { 36 | return t.failure(u, c) 37 | } 38 | try { 39 | return t.success(BigInt(s)) 40 | } catch (error) { 41 | return t.failure(u, c) 42 | } 43 | }) 44 | ), 45 | String 46 | ) 47 | -------------------------------------------------------------------------------- /dtslint/ts3.5/index.ts: -------------------------------------------------------------------------------- 1 | import { ordNumber } from 'fp-ts/lib/Ord' 2 | import * as t from 'io-ts' 3 | import { either, nonEmptyArray, NumberFromString, option, optionFromNullable, setFromArray, Json } from '../../src' 4 | 5 | // 6 | // either 7 | // 8 | 9 | const E = either(t.string, NumberFromString) 10 | type EA = t.TypeOf // $ExpectType Either 11 | type EO = t.OutputOf // $ExpectType EitherOutput 12 | 13 | // 14 | // nonEmptyArray 15 | // 16 | 17 | const NEA = nonEmptyArray(NumberFromString) 18 | type NEAA = t.TypeOf // $ExpectType NonEmptyArray 19 | type NEAO = t.OutputOf // $ExpectType NonEmptyArray 20 | 21 | nonEmptyArray(t.unknown).pipe(nonEmptyArray(t.unknown)) 22 | 23 | // 24 | // option 25 | // 26 | 27 | const O = option(NumberFromString) 28 | type OA = t.TypeOf // $ExpectType Option 29 | type OO = t.OutputOf // $ExpectType OptionOutput 30 | 31 | // 32 | // optionFromNullable 33 | // 34 | 35 | const OFN = optionFromNullable(NumberFromString) 36 | type OFNA = t.TypeOf // $ExpectType Option 37 | type OFNO = t.OutputOf // $ExpectType string | null 38 | 39 | // 40 | // setFromArray 41 | // 42 | 43 | const SFA = setFromArray(NumberFromString, ordNumber) 44 | type SFAA = t.TypeOf // $ExpectType Set 45 | type SFAO = t.OutputOf // $ExpectType string[] 46 | 47 | // 48 | // Json.pipe 49 | // 50 | const JO = Json.pipe(option(t.string)) // $ExpectType Type, Json, unknown> 51 | const JE = Json.pipe(either(t.string, t.number)) // $ExpectType Type, Json, unknown> 52 | -------------------------------------------------------------------------------- /docs/modules/JsonFromString.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: JsonFromString.ts 3 | nav_order: 16 4 | parent: Modules 5 | --- 6 | 7 | # JsonFromString overview 8 | 9 | Added in v0.5.14 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [JsonArray (interface)](#jsonarray-interface) 16 | - [JsonRecord (interface)](#jsonrecord-interface) 17 | - [Json (type alias)](#json-type-alias) 18 | - [Json](#json) 19 | - [JsonArray](#jsonarray) 20 | - [JsonFromString](#jsonfromstring) 21 | - [JsonRecord](#jsonrecord) 22 | 23 | --- 24 | 25 | # JsonArray (interface) 26 | 27 | **Signature** 28 | 29 | ```ts 30 | export interface JsonArray extends ReadonlyArray {} 31 | ``` 32 | 33 | Added in v0.5.14 34 | 35 | # JsonRecord (interface) 36 | 37 | **Signature** 38 | 39 | ```ts 40 | export interface JsonRecord { 41 | readonly [key: string]: Json 42 | } 43 | ``` 44 | 45 | Added in v0.5.14 46 | 47 | # Json (type alias) 48 | 49 | Copied from `fp-ts/Either` module. 50 | 51 | **Signature** 52 | 53 | ```ts 54 | export type Json = boolean | number | string | null | JsonArray | JsonRecord 55 | ``` 56 | 57 | Added in v0.5.14 58 | 59 | # Json 60 | 61 | **Signature** 62 | 63 | ```ts 64 | export const Json: t.Type = ... 65 | ``` 66 | 67 | Added in v0.5.15 68 | 69 | # JsonArray 70 | 71 | **Signature** 72 | 73 | ```ts 74 | export const JsonArray: t.Type = ... 75 | ``` 76 | 77 | Added in v0.5.15 78 | 79 | # JsonFromString 80 | 81 | **Signature** 82 | 83 | ```ts 84 | export const JsonFromString: t.Type = ... 85 | ``` 86 | 87 | Added in v0.5.14 88 | 89 | # JsonRecord 90 | 91 | **Signature** 92 | 93 | ```ts 94 | export const JsonRecord: t.Type = ... 95 | ``` 96 | 97 | Added in v0.5.15 98 | -------------------------------------------------------------------------------- /docs/modules/NonEmptyString.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: NonEmptyString.ts 3 | nav_order: 20 4 | parent: Modules 5 | --- 6 | 7 | # NonEmptyString overview 8 | 9 | Added in v0.4.5 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [NonEmptyStringBrand (interface)](#nonemptystringbrand-interface) 16 | - [NonEmptyStringC (interface)](#nonemptystringc-interface) 17 | - [NonEmptyString (type alias)](#nonemptystring-type-alias) 18 | - [NonEmptyString](#nonemptystring) 19 | 20 | --- 21 | 22 | # NonEmptyStringBrand (interface) 23 | 24 | **Signature** 25 | 26 | ```ts 27 | export interface NonEmptyStringBrand { 28 | readonly NonEmptyString: unique symbol 29 | } 30 | ``` 31 | 32 | Added in v0.4.5 33 | 34 | # NonEmptyStringC (interface) 35 | 36 | **Signature** 37 | 38 | ```ts 39 | export interface NonEmptyStringC extends t.Type {} 40 | ``` 41 | 42 | Added in v0.4.5 43 | 44 | # NonEmptyString (type alias) 45 | 46 | **Signature** 47 | 48 | ```ts 49 | export type NonEmptyString = t.Branded 50 | ``` 51 | 52 | Added in v0.4.5 53 | 54 | # NonEmptyString 55 | 56 | A codec that succeeds if a string is not empty 57 | 58 | **Signature** 59 | 60 | ```ts 61 | export const NonEmptyString: NonEmptyStringC = ... 62 | ``` 63 | 64 | **Example** 65 | 66 | ```ts 67 | import { NonEmptyString } from 'io-ts-types/lib/NonEmptyString' 68 | import { right } from 'fp-ts/lib/Either' 69 | import { PathReporter } from 'io-ts/lib/PathReporter' 70 | 71 | assert.deepStrictEqual(NonEmptyString.decode('a'), right('a')) 72 | assert.deepStrictEqual(PathReporter.report(NonEmptyString.decode('')), [ 73 | 'Invalid value "" supplied to : NonEmptyString' 74 | ]) 75 | ``` 76 | 77 | Added in v0.4.5 78 | -------------------------------------------------------------------------------- /test/setFromArray.ts: -------------------------------------------------------------------------------- 1 | import { setFromArray } from '../src' 2 | import * as t from 'io-ts' 3 | import * as assert from 'assert' 4 | import { assertFailure, assertSuccess } from './helpers' 5 | import { ordNumber } from 'fp-ts/lib/Ord' 6 | 7 | describe('setFromArray', () => { 8 | it('name', () => { 9 | const T = setFromArray(t.number, ordNumber, 'T') 10 | assert.strictEqual(T.name, 'T') 11 | }) 12 | 13 | it('is', () => { 14 | const T = setFromArray(t.number, ordNumber) 15 | assert.deepStrictEqual(T.is(null), false) 16 | assert.deepStrictEqual(T.is(new Set()), true) 17 | assert.deepStrictEqual(T.is(new Set([])), true) 18 | assert.deepStrictEqual(T.is(new Set([1])), true) 19 | assert.deepStrictEqual(T.is(new Set([1, 1])), true) 20 | assert.deepStrictEqual(T.is(new Set([1, 2])), true) 21 | assert.deepStrictEqual(T.is(new Set([1, '1'])), false) 22 | }) 23 | 24 | it('decode', () => { 25 | const T = setFromArray(t.number, ordNumber) 26 | assertSuccess(T.decode([]), new Set()) 27 | assertSuccess(T.decode([1]), new Set([1])) 28 | assertSuccess(T.decode([1, 2, 3]), new Set([1, 2, 3])) 29 | assertFailure(T, [1, 1], ['Invalid value [1,1] supplied to : Set']) 30 | assertFailure(T, null, ['Invalid value null supplied to : Set']) 31 | assertFailure(T, [1, 'a'], ['Invalid value "a" supplied to : Set/1: number']) 32 | }) 33 | 34 | it('encode', () => { 35 | const T = setFromArray(t.number, ordNumber) 36 | assert.deepStrictEqual(T.encode(new Set([1, 2, 3])), [1, 2, 3]) 37 | assert.deepStrictEqual(T.encode(new Set([1])), [1]) 38 | assert.deepStrictEqual(T.encode(new Set([])), []) 39 | assert.deepStrictEqual(T.encode(new Set()), []) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /test/JsonFromString.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { JsonFromString, JsonArray } from '../src' 3 | import { assertFailure, assertSuccess } from './helpers' 4 | import * as t from 'io-ts' 5 | 6 | describe('JSONFromString', () => { 7 | it('is', () => { 8 | const T = JsonFromString 9 | assert.deepStrictEqual(T.is(null), true) 10 | assert.deepStrictEqual(T.is('a'), true) 11 | assert.deepStrictEqual(T.is(1), true) 12 | assert.deepStrictEqual(T.is(true), true) 13 | assert.deepStrictEqual(T.is(false), true) 14 | assert.deepStrictEqual(T.is([]), true) 15 | assert.deepStrictEqual(T.is([1]), true) 16 | assert.deepStrictEqual(T.is({}), true) 17 | assert.deepStrictEqual(T.is({ a: 1 }), true) 18 | assert.deepStrictEqual(T.is({ a: Date }), false) 19 | }) 20 | 21 | it('decode', () => { 22 | const T = JsonFromString 23 | assertSuccess(T.decode('null'), null) 24 | assertSuccess(T.decode('1'), 1) 25 | assertSuccess(T.decode('"a"'), 'a') 26 | assertSuccess(T.decode('true'), true) 27 | assertSuccess(T.decode('false'), false) 28 | assertSuccess(T.decode('[]'), []) 29 | assertSuccess(T.decode('{}'), {}) 30 | assertFailure(T, '{', ['Invalid value "{" supplied to : JsonFromString']) 31 | assertFailure(T, '{"a":undefined}', ['Invalid value "{\\"a\\":undefined}" supplied to : JsonFromString']) 32 | }) 33 | 34 | it('encode', () => { 35 | const T = JsonFromString 36 | assert.deepEqual(T.encode({}), '{}') 37 | }) 38 | 39 | it('#156', () => { 40 | const C = JsonFromString.pipe( 41 | t.type({ 42 | a: JsonArray 43 | }) 44 | ) 45 | assertSuccess(C.decode('{"a":[]}'), { a: [] }) 46 | assertFailure(C, '{"a":1}', ['Invalid value 1 supplied to : pipe(JsonFromString, { a: JsonArray })/a: JsonArray']) 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /src/option.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import { Option } from 'fp-ts/lib/Option' 5 | import * as t from 'io-ts' 6 | 7 | const None = t.strict( 8 | { 9 | _tag: t.literal('None') 10 | }, 11 | 'None' 12 | ) 13 | 14 | const someLiteral = t.literal('Some') 15 | 16 | /** 17 | * @since 0.5.18 18 | */ 19 | export type NoneOutput = t.OutputOf 20 | 21 | /** 22 | * @since 0.5.18 23 | */ 24 | export type SomeOutput
= { _tag: 'Some'; value: A } 25 | 26 | /** 27 | * @since 0.5.18 28 | */ 29 | export type OptionOutput = NoneOutput | SomeOutput 30 | 31 | /** 32 | * Given a codec representing a type `A`, returns a codec representing `Option` that is able to deserialize 33 | * the JSON representation of an `Option`. 34 | * 35 | * @example 36 | * import { option } from 'io-ts-types/lib/option' 37 | * import { right } from 'fp-ts/lib/Either' 38 | * import { none, some } from 'fp-ts/lib/Option' 39 | * import * as t from 'io-ts' 40 | * import { PathReporter } from 'io-ts/lib/PathReporter' 41 | * 42 | * const T = option(t.number) 43 | * 44 | * assert.deepStrictEqual(T.decode(none), right(none)) 45 | * assert.deepStrictEqual(T.decode(some(1)), right(some(1))) 46 | * assert.deepStrictEqual(PathReporter.report(T.decode(some('a'))), ['Invalid value "a" supplied to : Option/1: Some/value: number']) 47 | * 48 | * @since 0.5.0 49 | */ 50 | export interface OptionC extends t.Type>, OptionOutput>, unknown> {} 51 | 52 | /** 53 | * @since 0.5.0 54 | */ 55 | export function option(codec: C, name: string = `Option<${codec.name}>`): OptionC { 56 | return t.union( 57 | [ 58 | None, 59 | t.strict( 60 | { 61 | _tag: someLiteral, 62 | value: codec 63 | }, 64 | `Some<${codec.name}>` 65 | ) 66 | ], 67 | name 68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /src/mapFromEntries.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.19 3 | */ 4 | import * as A from 'fp-ts/lib/Array' 5 | import { chain } from 'fp-ts/lib/Either' 6 | import { fromFoldable, toArray } from 'fp-ts/lib/Map' 7 | import { Ord } from 'fp-ts/Ord' 8 | import { getLastSemigroup } from 'fp-ts/lib/Semigroup' 9 | import { pipe, Predicate } from 'fp-ts/function' 10 | import * as t from 'io-ts' 11 | 12 | interface Next { 13 | readonly done?: boolean 14 | readonly value: A 15 | } 16 | 17 | const every = (pk: Predicate, pv: Predicate) => (ma: Map): boolean => { 18 | const entries = ma.entries() 19 | let e: Next<[K, V]> 20 | while (!(e = entries.next()).done) { 21 | if (pk(e.value[0]) === false || pv(e.value[1]) === false) { 22 | return false 23 | } 24 | } 25 | return true 26 | } 27 | 28 | /** 29 | * @since 0.5.19 30 | */ 31 | export interface MapFromEntriesC 32 | extends t.Type, t.TypeOf>, Array<[t.OutputOf, t.OutputOf]>, unknown> {} 33 | 34 | /** 35 | * @since 0.5.19 36 | */ 37 | export function mapFromEntries( 38 | keyCodec: K, 39 | KO: Ord>, 40 | valueCodec: V, 41 | name: string = `Map<${keyCodec.name}, ${valueCodec.name}>` 42 | ): MapFromEntriesC { 43 | const arr = t.array(t.tuple([keyCodec, valueCodec])) 44 | const toArrayO = toArray(KO) 45 | const fromArrayO = fromFoldable(KO, getLastSemigroup>(), A.Foldable) 46 | const everyO = every(keyCodec.is, valueCodec.is) 47 | return new t.Type( 48 | name, 49 | (u): u is Map, t.TypeOf> => u instanceof Map && everyO(u), 50 | (u, c) => 51 | pipe( 52 | arr.validate(u, c), 53 | chain(as => { 54 | const map = fromArrayO(as) 55 | return map.size !== as.length ? t.failure(u, c) : t.success(map) 56 | }) 57 | ), 58 | a => arr.encode(toArrayO(a)) 59 | ) 60 | } 61 | -------------------------------------------------------------------------------- /test/option.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { none, some } from 'fp-ts/lib/Option' 3 | import * as t from 'io-ts' 4 | import { NumberFromString } from '../src' 5 | import { option } from '../src' 6 | import { assertFailure, assertSuccess } from './helpers' 7 | 8 | describe('option', () => { 9 | it('name', () => { 10 | const T = option(t.number, 'T') 11 | assert.strictEqual(T.name, 'T') 12 | }) 13 | 14 | it('is', () => { 15 | const T1 = option(t.number) 16 | assert.strictEqual(T1.is(some(1)), true) 17 | assert.strictEqual(T1.is(some('foo')), false) 18 | }) 19 | 20 | it('decode', () => { 21 | const T1 = option(t.number) 22 | assertSuccess(T1.decode(none), none) 23 | assertSuccess(T1.decode(some(1)), some(1)) 24 | assertFailure(T1, some('a'), ['Invalid value "a" supplied to : Option/1: Some/value: number']) 25 | 26 | const T2 = option(NumberFromString) 27 | assertSuccess(T2.decode(none), none) 28 | assertSuccess(T2.decode(some('1')), some(1)) 29 | 30 | const T3 = option(option(t.number)) 31 | assertSuccess(T3.decode({ _tag: 'Some', value: { _tag: 'Some', value: 1 } }), some(some(1))) 32 | assertSuccess(T3.decode({ _tag: 'Some', value: { _tag: 'None' } }), some(none)) 33 | assertSuccess(T3.decode({ _tag: 'None' }), none) 34 | }) 35 | 36 | it('encode', () => { 37 | const T1 = option(t.number) 38 | assert.deepStrictEqual(T1.encode(none), none) 39 | assert.deepStrictEqual(T1.encode(some(1)), some(1)) 40 | 41 | const T2 = option(NumberFromString) 42 | assert.deepStrictEqual(T2.encode(none), none) 43 | assert.deepStrictEqual(T2.encode(some(1)), some('1')) 44 | 45 | const T3 = option(option(t.number)) 46 | assert.deepStrictEqual(T3.encode(none), { _tag: 'None' }) 47 | assert.deepStrictEqual(T3.encode(some(some(1))), { _tag: 'Some', value: { _tag: 'Some', value: 1 } }) 48 | assert.deepStrictEqual(T3.encode(some(none)), { _tag: 'Some', value: { _tag: 'None' } }) 49 | }) 50 | }) 51 | -------------------------------------------------------------------------------- /test/mapFromEntries.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert' 2 | import { pipe } from 'fp-ts/function' 3 | import { Ord, ordString, contramap } from 'fp-ts/Ord' 4 | import * as t from 'io-ts' 5 | import { assertSuccess, assertFailure } from './helpers' 6 | 7 | import { mapFromEntries } from '../src/mapFromEntries' 8 | 9 | describe('mapFromEntries', () => { 10 | const K = t.type({ a: t.string }) 11 | const KO: Ord> = pipe( 12 | ordString, 13 | contramap(m => m.a) 14 | ) 15 | const C = t.type({ b: t.number }) 16 | const T = mapFromEntries(K, KO, C) 17 | 18 | it('name', () => { 19 | const T = mapFromEntries(K, KO, C, 'T') 20 | assert.strictEqual(T.name, 'T') 21 | }) 22 | 23 | it('is', () => { 24 | assert.strictEqual(T.is(new Map()), true) 25 | assert.strictEqual(T.is(new Map([[{ a: 'a' }, { b: 1 }]])), true) 26 | assert.strictEqual(T.is(null), false) 27 | assert.strictEqual(T.is(undefined), false) 28 | assert.strictEqual(T.is({}), false) 29 | assert.strictEqual(T.is([]), false) 30 | assert.strictEqual(T.is(new Map([['a', 'b']])), false) 31 | assert.strictEqual(T.is(new Map([['a', { b: 1 }]])), false) 32 | assert.strictEqual(T.is(new Map([[{ a: 'a' }, 1]])), false) 33 | }) 34 | 35 | it('decode', () => { 36 | assertSuccess(T.decode([]), new Map()) 37 | assertSuccess( 38 | T.decode([[{ a: '1' }, { b: 1 }], [{ a: '2' }, { b: 2 }]]), 39 | new Map([[{ a: '1' }, { b: 1 }], [{ a: '2' }, { b: 2 }]]) 40 | ) 41 | assertFailure( 42 | T, 43 | [[{ a: '1' }, { b: 1 }], [{ a: '1' }, { b: 2 }]], 44 | ['Invalid value [[{"a":"1"},{"b":1}],[{"a":"1"},{"b":2}]] supplied to : Map<{ a: string }, { b: number }>'] 45 | ) 46 | }) 47 | 48 | it('encode', () => { 49 | assert.deepStrictEqual(T.encode(new Map()), []) 50 | assert.deepStrictEqual(T.encode(new Map([[{ a: '1' }, { b: 1 }], [{ a: '2' }, { b: 2 }]])), [ 51 | [{ a: '1' }, { b: 1 }], 52 | [{ a: '2' }, { b: 2 }] 53 | ]) 54 | }) 55 | }) 56 | -------------------------------------------------------------------------------- /src/either.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.0 3 | */ 4 | import { Either } from 'fp-ts/lib/Either' 5 | import * as t from 'io-ts' 6 | 7 | const leftLiteral = t.literal('Left') 8 | 9 | const rightLiteral = t.literal('Right') 10 | 11 | /** 12 | * @since 0.5.18 13 | */ 14 | export type LeftOutput = { _tag: 'Left'; left: L } 15 | 16 | /** 17 | * @since 0.5.18 18 | */ 19 | export type RightOutput = { _tag: 'Right'; right: R } 20 | 21 | /** 22 | * @since 0.5.18 23 | */ 24 | export type EitherOutput = LeftOutput | RightOutput 25 | 26 | /** 27 | * @since 0.5.0 28 | */ 29 | export interface EitherC 30 | extends t.Type, t.TypeOf>, EitherOutput, t.OutputOf>, unknown> {} 31 | 32 | /** 33 | * Given a codec representing a type `L` and a codec representing a type `A`, returns a codec representing `Either` that is able to deserialize 34 | * the JSON representation of an `Either`. 35 | * 36 | * @example 37 | * import { either } from 'io-ts-types/lib/either' 38 | * import { left, right } from 'fp-ts/lib/Either' 39 | * import * as t from 'io-ts' 40 | * import { PathReporter } from 'io-ts/lib/PathReporter' 41 | * 42 | * const T = either(t.string, t.number) 43 | * 44 | * assert.deepStrictEqual(T.decode(right(1)), right(right(1))) 45 | * assert.deepStrictEqual(T.decode(left('a')), right(left('a'))) 46 | * assert.deepStrictEqual(PathReporter.report(T.decode(right('a'))), ['Invalid value "a" supplied to : Either/1: Right/right: number']) 47 | * 48 | * @since 0.5.0 49 | */ 50 | export function either( 51 | leftCodec: L, 52 | rightCodec: R, 53 | name: string = `Either<${leftCodec.name}, ${rightCodec.name}>` 54 | ): EitherC { 55 | return t.union( 56 | [ 57 | t.strict( 58 | { 59 | _tag: leftLiteral, 60 | left: leftCodec 61 | }, 62 | `Left<${leftCodec.name}>` 63 | ), 64 | t.strict( 65 | { 66 | _tag: rightLiteral, 67 | right: rightCodec 68 | }, 69 | `Right<${leftCodec.name}>` 70 | ) 71 | ], 72 | name 73 | ) 74 | } 75 | -------------------------------------------------------------------------------- /docs/modules/option.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: option.ts 3 | nav_order: 22 4 | parent: Modules 5 | --- 6 | 7 | # option overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [OptionC (interface)](#optionc-interface) 16 | - [NoneOutput (type alias)](#noneoutput-type-alias) 17 | - [OptionOutput (type alias)](#optionoutput-type-alias) 18 | - [SomeOutput (type alias)](#someoutput-type-alias) 19 | - [option](#option) 20 | 21 | --- 22 | 23 | # OptionC (interface) 24 | 25 | Given a codec representing a type `A`, returns a codec representing `Option
` that is able to deserialize 26 | the JSON representation of an `Option`. 27 | 28 | **Signature** 29 | 30 | ```ts 31 | export interface OptionC extends t.Type>, OptionOutput>, unknown> {} 32 | ``` 33 | 34 | **Example** 35 | 36 | ```ts 37 | import { option } from 'io-ts-types/lib/option' 38 | import { right } from 'fp-ts/lib/Either' 39 | import { none, some } from 'fp-ts/lib/Option' 40 | import * as t from 'io-ts' 41 | import { PathReporter } from 'io-ts/lib/PathReporter' 42 | 43 | const T = option(t.number) 44 | 45 | assert.deepStrictEqual(T.decode(none), right(none)) 46 | assert.deepStrictEqual(T.decode(some(1)), right(some(1))) 47 | assert.deepStrictEqual(PathReporter.report(T.decode(some('a'))), [ 48 | 'Invalid value "a" supplied to : Option/1: Some/value: number' 49 | ]) 50 | ``` 51 | 52 | Added in v0.5.0 53 | 54 | # NoneOutput (type alias) 55 | 56 | **Signature** 57 | 58 | ```ts 59 | export type NoneOutput = t.OutputOf 60 | ``` 61 | 62 | Added in v0.5.18 63 | 64 | # OptionOutput (type alias) 65 | 66 | **Signature** 67 | 68 | ```ts 69 | export type OptionOutput = NoneOutput | SomeOutput 70 | ``` 71 | 72 | Added in v0.5.18 73 | 74 | # SomeOutput (type alias) 75 | 76 | **Signature** 77 | 78 | ```ts 79 | export type SomeOutput = { _tag: 'Some'; value: A } 80 | ``` 81 | 82 | Added in v0.5.18 83 | 84 | # option 85 | 86 | **Signature** 87 | 88 | ```ts 89 | export function option(codec: C, name: string = `Option<${codec.name}>`): OptionC { ... } 90 | ``` 91 | 92 | Added in v0.5.0 93 | -------------------------------------------------------------------------------- /docs/modules/either.ts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: either.ts 3 | nav_order: 9 4 | parent: Modules 5 | --- 6 | 7 | # either overview 8 | 9 | Added in v0.5.0 10 | 11 | --- 12 | 13 |

Table of contents

14 | 15 | - [EitherC (interface)](#eitherc-interface) 16 | - [EitherOutput (type alias)](#eitheroutput-type-alias) 17 | - [LeftOutput (type alias)](#leftoutput-type-alias) 18 | - [RightOutput (type alias)](#rightoutput-type-alias) 19 | - [either](#either) 20 | 21 | --- 22 | 23 | # EitherC (interface) 24 | 25 | **Signature** 26 | 27 | ```ts 28 | export interface EitherC 29 | extends t.Type, t.TypeOf>, EitherOutput, t.OutputOf>, unknown> {} 30 | ``` 31 | 32 | Added in v0.5.0 33 | 34 | # EitherOutput (type alias) 35 | 36 | **Signature** 37 | 38 | ```ts 39 | export type EitherOutput = LeftOutput | RightOutput 40 | ``` 41 | 42 | Added in v0.5.18 43 | 44 | # LeftOutput (type alias) 45 | 46 | **Signature** 47 | 48 | ```ts 49 | export type LeftOutput = { _tag: 'Left'; left: L } 50 | ``` 51 | 52 | Added in v0.5.18 53 | 54 | # RightOutput (type alias) 55 | 56 | **Signature** 57 | 58 | ```ts 59 | export type RightOutput = { _tag: 'Right'; right: R } 60 | ``` 61 | 62 | Added in v0.5.18 63 | 64 | # either 65 | 66 | Given a codec representing a type `L` and a codec representing a type `A`, returns a codec representing `Either` that is able to deserialize 67 | the JSON representation of an `Either`. 68 | 69 | **Signature** 70 | 71 | ```ts 72 | export function either( 73 | leftCodec: L, 74 | rightCodec: R, 75 | name: string = `Either<${leftCodec.name}, ${rightCodec.name}>` 76 | ): EitherC { ... } 77 | ``` 78 | 79 | **Example** 80 | 81 | ```ts 82 | import { either } from 'io-ts-types/lib/either' 83 | import { left, right } from 'fp-ts/lib/Either' 84 | import * as t from 'io-ts' 85 | import { PathReporter } from 'io-ts/lib/PathReporter' 86 | 87 | const T = either(t.string, t.number) 88 | 89 | assert.deepStrictEqual(T.decode(right(1)), right(right(1))) 90 | assert.deepStrictEqual(T.decode(left('a')), right(left('a'))) 91 | assert.deepStrictEqual(PathReporter.report(T.decode(right('a'))), [ 92 | 'Invalid value "a" supplied to : Either/1: Right/right: number' 93 | ]) 94 | ``` 95 | 96 | Added in v0.5.0 97 | -------------------------------------------------------------------------------- /scripts/build.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path' 2 | import * as E from 'fp-ts/Either' 3 | import { pipe } from 'fp-ts/function' 4 | import * as RTE from 'fp-ts/ReaderTaskEither' 5 | import * as A from 'fp-ts/ReadonlyArray' 6 | import * as TE from 'fp-ts/TaskEither' 7 | import { FileSystem, fileSystem } from './FileSystem' 8 | import { run } from './run' 9 | 10 | interface Build
extends RTE.ReaderTaskEither {} 11 | 12 | const OUTPUT_FOLDER = 'dist' 13 | const PKG = 'package.json' 14 | 15 | export const copyPackageJson: Build = (C) => 16 | pipe( 17 | C.readFile(PKG), 18 | TE.chain((s) => TE.fromEither(E.parseJSON(s, E.toError))), 19 | TE.map((v) => { 20 | const clone = Object.assign({}, v as any) 21 | 22 | delete clone.scripts 23 | delete clone.files 24 | delete clone.devDependencies 25 | 26 | return clone 27 | }), 28 | TE.chain((json) => C.writeFile(path.join(OUTPUT_FOLDER, PKG), JSON.stringify(json, null, 2))) 29 | ) 30 | 31 | export const FILES: ReadonlyArray = ['CHANGELOG.md', 'LICENSE', 'README.md'] 32 | 33 | export const copyFiles: Build> = (C) => 34 | pipe( 35 | FILES, 36 | A.traverse(TE.taskEither)((from) => C.copyFile(from, path.resolve(OUTPUT_FOLDER, from))) 37 | ) 38 | 39 | const traverse = A.traverse(TE.taskEither) 40 | 41 | export const makeModules: Build = (C) => 42 | pipe( 43 | C.glob(`${OUTPUT_FOLDER}/lib/*.js`), 44 | TE.map(getModules), 45 | TE.chain(traverse(makeSingleModule(C))), 46 | TE.map(() => undefined) 47 | ) 48 | 49 | function getModules(paths: ReadonlyArray): ReadonlyArray { 50 | return paths.map((filePath) => path.basename(filePath, '.js')).filter((x) => x !== 'index') 51 | } 52 | 53 | function makeSingleModule(C: FileSystem): (module: string) => TE.TaskEither { 54 | return (m) => 55 | pipe( 56 | C.mkdir(path.join(OUTPUT_FOLDER, m)), 57 | TE.chain(() => makePkgJson(m)), 58 | TE.chain((data) => C.writeFile(path.join(OUTPUT_FOLDER, m, 'package.json'), data)) 59 | ) 60 | } 61 | 62 | function makePkgJson(module: string): TE.TaskEither { 63 | return pipe( 64 | JSON.stringify( 65 | { 66 | main: `../lib/${module}.js`, 67 | module: `../es6/${module}.js`, 68 | typings: `../lib/${module}.d.ts`, 69 | sideEffects: false 70 | }, 71 | null, 72 | 2 73 | ), 74 | TE.right 75 | ) 76 | } 77 | 78 | const main: Build = pipe( 79 | copyPackageJson, 80 | RTE.chain(() => copyFiles), 81 | RTE.chain(() => makeModules) 82 | ) 83 | 84 | run( 85 | main({ 86 | ...fileSystem 87 | }) 88 | ) 89 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @since 0.5.8 3 | */ 4 | export * from './mapOutput' 5 | 6 | /** 7 | * @since 0.5.8 8 | */ 9 | export * from './NonEmptyString' 10 | 11 | /** 12 | * @since 0.5.8 13 | */ 14 | export * from './nonEmptyArray' 15 | 16 | /** 17 | * @since 0.5.8 18 | */ 19 | export * from './readonlySetFromArray' 20 | 21 | /** 22 | * @since 0.5.8 23 | */ 24 | export * from './fromRefinement' 25 | 26 | /** 27 | * @since 0.5.8 28 | */ 29 | export * from './date' 30 | 31 | /** 32 | * @since 0.5.8 33 | */ 34 | export * from './fromNewtype' 35 | 36 | /** 37 | * @since 0.5.8 38 | */ 39 | export * from './optionFromNullable' 40 | 41 | /** 42 | * @since 0.5.8 43 | */ 44 | export * from './DateFromISOString' 45 | 46 | /** 47 | * @since 0.5.8 48 | */ 49 | export * from './readonlyNonEmptyArray' 50 | 51 | /** 52 | * @since 0.5.8 53 | */ 54 | export * from './clone' 55 | 56 | /** 57 | * @since 0.5.8 58 | */ 59 | export * from './DateFromNumber' 60 | 61 | /** 62 | * @since 0.5.8 63 | */ 64 | export * from './withFallback' 65 | 66 | /** 67 | * @since 0.5.8 68 | */ 69 | export * from './UUID' 70 | 71 | /** 72 | * @since 0.5.8 73 | */ 74 | export * from './fromNullable' 75 | 76 | /** 77 | * @since 0.5.8 78 | */ 79 | export * from './BooleanFromString' 80 | 81 | /** 82 | * @since 0.5.8 83 | */ 84 | export * from './withMessage' 85 | 86 | /** 87 | * @since 0.5.8 88 | */ 89 | export * from './withValidate' 90 | 91 | /** 92 | * @since 0.5.8 93 | */ 94 | export * from './getLenses' 95 | 96 | /** 97 | * @since 0.5.8 98 | */ 99 | export * from './regexp' 100 | 101 | /** 102 | * @since 0.5.8 103 | */ 104 | export * from './option' 105 | 106 | /** 107 | * @since 0.5.8 108 | */ 109 | export * from './DateFromUnixTime' 110 | 111 | /** 112 | * @since 0.5.8 113 | */ 114 | export * from './NumberFromString' 115 | 116 | /** 117 | * @since 0.5.8 118 | */ 119 | export * from './setFromArray' 120 | 121 | /** 122 | * @since 0.5.8 123 | */ 124 | export * from './IntFromString' 125 | 126 | /** 127 | * @since 0.5.14 128 | */ 129 | export * from './JsonFromString' 130 | 131 | /** 132 | * @since 0.5.8 133 | */ 134 | export * from './either' 135 | 136 | /** 137 | * @since 0.5.11 138 | */ 139 | export * from './BigIntFromString' 140 | 141 | /** 142 | * @since 0.5.12 143 | */ 144 | export * from './withEncode' 145 | 146 | /** 147 | * @since 0.5.13 148 | */ 149 | export * from './BooleanFromNumber' 150 | 151 | /** 152 | * @since 0.5.18 153 | */ 154 | export * from './mapFromEntries' 155 | 156 | /** 157 | * @since 0.5.18 158 | */ 159 | export * from './readonlyMapFromEntries' 160 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "io-ts-types", 3 | "version": "0.5.19", 4 | "description": "A collection of codecs and combinators for use with io-ts", 5 | "main": "lib/index.js", 6 | "module": "es6/index.js", 7 | "typings": "lib/index.d.ts", 8 | "sideEffects": false, 9 | "scripts": { 10 | "lint": "tslint -p tsconfig.json src/**/*.ts test/**/*.ts", 11 | "prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --list-different \"{src,test}/**/*.ts\" || { echo \"Failure due to formatting, please run 'npm run fix-prettier' to fix this issue\"; exit 1; }", 12 | "fix-prettier": "prettier --no-semi --single-quote --print-width 120 --parser typescript --write \"{src,test}/**/*.ts\"", 13 | "jest": "jest --ci", 14 | "test": "npm run build && npm run lint && npm run dtslint && npm run prettier && npm run jest && npm run docs", 15 | "clean": "rm -rf ./dist", 16 | "prebuild": "npm run clean", 17 | "build": "tsc -p ./tsconfig.build.json && tsc -p ./tsconfig.build-es6.json && npm run import-path-rewrite && ts-node scripts/build", 18 | "postbuild": "prettier --loglevel=silent --write \"./dist/**/*.ts\"", 19 | "prepublishOnly": "ts-node scripts/pre-publish", 20 | "dtslint": "dtslint dtslint", 21 | "mocha": "mocha -r ts-node/register test/*.ts", 22 | "docs": "docs-ts", 23 | "prerelease": "npm run build", 24 | "release": "ts-node scripts/release", 25 | "import-path-rewrite": "import-path-rewrite" 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "https://github.com/gcanti/io-ts-types.git" 30 | }, 31 | "author": "Giulio Canti ", 32 | "license": "MIT", 33 | "bugs": { 34 | "url": "https://github.com/gcanti/io-ts-types/issues" 35 | }, 36 | "homepage": "https://github.com/gcanti/io-ts-types", 37 | "peerDependencies": { 38 | "fp-ts": "^2.0.0", 39 | "io-ts": "^2.0.0", 40 | "monocle-ts": "^2.0.0", 41 | "newtype-ts": "^0.3.2" 42 | }, 43 | "devDependencies": { 44 | "@types/jest": "^24.0.15", 45 | "@types/node": "^14.0.27", 46 | "docs-ts": "^0.3.4", 47 | "dtslint": "github:gcanti/dtslint", 48 | "fp-ts": "^2.8.0", 49 | "import-path-rewrite": "github:gcanti/import-path-rewrite", 50 | "io-ts": "^2.0.0", 51 | "jest": "^24.8.0", 52 | "mocha": "^5.2.0", 53 | "monocle-ts": "^2.0.0", 54 | "newtype-ts": "^0.3.2", 55 | "prettier": "^1.16.1", 56 | "ts-jest": "^24.0.2", 57 | "ts-node": "3.2.1", 58 | "tslint": "^5.12.1", 59 | "tslint-config-standard": "^8.0.1", 60 | "typescript": "^3.9.3" 61 | }, 62 | "tags": [ 63 | "io-ts", 64 | "fp-ts", 65 | "monocle-ts", 66 | "newtype-ts" 67 | ], 68 | "keywords": [ 69 | "io-ts", 70 | "fp-ts", 71 | "monocle-ts", 72 | "newtype-ts" 73 | ] 74 | } 75 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | > **Tags:** 4 | > 5 | > - [New Feature] 6 | > - [Bug Fix] 7 | > - [Breaking Change] 8 | > - [Documentation] 9 | > - [Internal] 10 | > - [Polish] 11 | > - [Experimental] 12 | 13 | **Note**: Gaps between patch versions are faulty/broken releases. **Note**: A feature tagged as Experimental is in a 14 | high state of flux, you're at risk of it changing without notice. 15 | 16 | # 0.5.19 17 | 18 | - **New Feature** 19 | - add `mapFromEntries`, `readonlyMapFromEntries` codecs, #172 (@mlegenhausen) 20 | 21 | # 0.5.18 22 | 23 | - **Polish** 24 | - add output indexed types to option and either, #171 (@mlegenhausen) 25 | 26 | # 0.5.17 27 | 28 | - **Polish** 29 | - `nonEmptyArray`: change output type from `Array` to `NonEmptyArray`, #170 (@OliverJAsh) 30 | - `readonlyNonEmptyArray`: change output type from `ReadonlyArray` to `ReadonlyNonEmptyArray`, #170 (@OliverJAsh) 31 | 32 | # 0.5.16 33 | 34 | - **Bug Fix** 35 | - fix `DateFromUnixTime.encode` returning a floating point number, #160 (@saevarb) 36 | 37 | # 0.5.15 38 | 39 | - **Polish** 40 | - export `Json`, `JsonRecord`, `JsonArray` codecs from `JsonFromString` module, closes #156 (@gcanti) 41 | 42 | # 0.5.14 43 | 44 | - **New Feature** 45 | - add `JsonFromString`, closes #153 (@gcanti) 46 | 47 | # 0.5.13 48 | 49 | - **New Feature** 50 | - add `BooleanFromNumber`, #152 (@EricCrosson) 51 | 52 | # 0.5.12 53 | 54 | - **New Feature** 55 | - add `withEncode` combinator, #146 (@EricCrosson) 56 | 57 | # 0.5.11 58 | 59 | - **New Feature** 60 | - add `BigIntFromString` codec, #141 (@EricCrosson) 61 | 62 | # 0.5.10 63 | 64 | - **Polish** 65 | - expose modules without lib/es6 prefix, #137 (@osdiab) 66 | 67 | # 0.5.9 68 | 69 | - **Polish** 70 | - pass context to withMessage callback #136 (@johngeorgewright) 71 | 72 | # 0.5.8 73 | 74 | - **New Feature** 75 | - export each module's exports from the library entrypoint, closes #129 (@waynevanson) 76 | 77 | # 0.5.7 78 | 79 | - **New Feature** 80 | - add `readonlyNonEmptyArray` (@gcanti) 81 | - add `readonlySetFromArray` (@gcanti) 82 | 83 | # 0.5.6 84 | 85 | - **Polish** 86 | - `fromNewtype` 87 | - add support for branded types, #123 (@mlegenhausen) 88 | - **Internal** 89 | - upgrade to `typescript@3.8` (@gcanti) 90 | 91 | # 0.5.5 92 | 93 | - **Bug Fix** 94 | - add sideEffects field to package.json (@gcanti) 95 | 96 | # 0.5.4 97 | 98 | - **Bug Fix** 99 | - rewrite es6 imports (@gcanti) 100 | 101 | # 0.5.3 102 | 103 | - **New Feature** 104 | - Provide version with ES modules (@OliverJAsh) 105 | 106 | # 0.5.2 107 | 108 | - **New Feature** 109 | - add `fromNewtype`, closes #111 (@mlegenhausen) 110 | 111 | # 0.5.1 112 | 113 | - **Bug Fix** 114 | - remove source maps, fix #106 (@gcanti) 115 | 116 | # 0.5.0 117 | 118 | **Note**. `io-ts-types` depends on 119 | 120 | - [`fp-ts`](https://github.com/gcanti/fp-ts) 121 | - [`io-ts`](https://github.com/gcanti/io-ts) 122 | - [`monocle-ts`](https://github.com/gcanti/monocle-ts) 123 | 124 | starting from `0.5.0` you must install `fp-ts`, `io-ts` and `monocle-ts` manually (`fp-ts`, `io-ts` and `monocle-ts` are listed in `peerDependencies`) 125 | 126 | - **Breaking Change** 127 | - upgrade to `fp-ts@2`, `monocle-ts@2` and `io-ts@2.0.0` (@gcanti) 128 | - move `fp-ts@2`, `monocle-ts@2` and `io-ts@2.0.0` to `peerDependencies` (@gcanti) 129 | - remove `boolean` folder (@gcanti) 130 | - move `BooleanFromString` to top level 131 | - remove `date` folder (@gcanti) 132 | - move `date` to top level 133 | - move `DateFromISOString` to top level 134 | - move `DateFromNumber` to top level 135 | - move `DateFromUnixTime` to top level 136 | - remove `fp-ts` folder (@gcanti) 137 | - move `createEitherFromJSON` to top level and rename to `either` 138 | - move `createNonEmptyArrayFromArray` to top level and rename to `nonEmptyArray` 139 | - move `createOptionFromJSON` to top level and rename to `option` 140 | - remove `createStrMapFromDictionary` 141 | - move `createOptionFromNullable` to top level and rename to `optionFromNullable` 142 | - move `createSetFromArray` to top level and rename to `setFromArray` 143 | - remove `JSON` folder (@gcanti) 144 | - remove `monocle-ts` (@gcanti) 145 | - move `lensesFromInterface` to top level and renamed to `getLenses` (@gcanti) 146 | - remove `TypePrismIso` module (@gcanti) 147 | - remove `newtype-ts` folder (@gcanti) 148 | - remove `number` folder (@gcanti) 149 | - move `NumberFromString` to top level 150 | - move `IntegerFromString` to top level and rename to `IntFromString` 151 | - rename `eitherFromJSON` to `either` (@gcanti) 152 | - rename `optionFromJSON` to `option` (@gcanti) 153 | - uncurry `fromNullable` (@gcanti) 154 | - uncurry `fallback` and rename to `withFallback` (@gcanti) 155 | 156 | # 0.4.7 157 | 158 | - **Bug Fix** 159 | - bind `decode` to the provided `validate` in `withValidate`, fix #95 (@gcanti) 160 | 161 | # 0.4.6 162 | 163 | - **New Feature** 164 | - add `UUID` codec (@mlegenhausen) 165 | 166 | # 0.4.5 167 | 168 | - **New Feature** 169 | - add `NonEmptyString` codec (@gcanti) 170 | 171 | # 0.4.4 172 | 173 | - **New Feature** 174 | - add `optionFromJSON` combinator (@gcanti) 175 | - add `eitherFromJSON` combinator (@gcanti) 176 | - add `IntFromString` codec (@gcanti) 177 | - add `fromRefinement` combinator (@gcanti) 178 | - add `regexp` codec (@StefanoMagrassi) 179 | - **Deprecation** 180 | - deprecate `number/IntegerFromString` in favour of `IntFromString` (@gcanti) 181 | - deprecate `fp-ts/createOptionFromJSON` in favour of `optionFromJSON` (@gcanti) 182 | - deprecate `fp-ts/createEitherFromJSON` in favour of `eitherFromJSON` (@gcanti) 183 | 184 | # 0.4.3 185 | 186 | - **New Feature** 187 | - add `clone` (@gcanti) 188 | - add `withValidate` (@gcanti) 189 | - add `withMessage` (@gcanti) 190 | 191 | # 0.4.2 192 | 193 | - **Polish** 194 | - export all interfaces, fix #77 (@sledorze) 195 | 196 | # 0.4.1 197 | 198 | - **Polish** 199 | - apply `io-ts@1.6.x` interface pattern (@gcanti) 200 | 201 | # 0.4.0 202 | 203 | - **Bug fix** 204 | - switch to `io-ts` pattern, fix #67 (PR #71) (@gcanti) 205 | 206 | **Note**. This fix should **not** be a breaking change for most users. However since some signatures are changed, namely their type parameters, this release is published with a minor bump as a precaution. 207 | 208 | # 0.3.14 209 | 210 | - **New Feature** 211 | - add `Date/date` (@mlegenhausen) 212 | 213 | # 0.3.13 214 | 215 | - **New Feature** 216 | - Export Codec class Types alongside their combinator, https://github.com/gcanti/io-ts-types/pull/63 (@sledorze) 217 | 218 | # 0.3.12 219 | 220 | - **Internal** 221 | - fix broken build with `typescript@3.1-rc`, closes #61 (@sledorze) 222 | 223 | # 0.3.11 224 | 225 | - **New Feature** 226 | - add `boolean/BooleanFromString`, fixes #55 (@sledorze) 227 | 228 | # 0.3.10 229 | 230 | - **New Feature** 231 | - add `fallback`, fixes #49 (@sledorze) 232 | - add `fromNullable`, closes #51 (@sledorze) 233 | 234 | # 0.3.9 235 | 236 | - **New Feature** 237 | - add `string/UUID` (@mlegenhausen) 238 | 239 | # 0.3.8 240 | 241 | - **New Feature** 242 | - add `newtype-ts/fromRefinement` (@gcanti) 243 | - add `newtype-ts/fromNewtypeCurried`, closes #44 (@gcanti) 244 | 245 | # 0.3.6 246 | 247 | - **Bug Fix** 248 | - fix `NumberFromString` validation, closes #40 (@sledorze) 249 | - **Internal** 250 | - simplify `lensesFromInterface` typings, closes #37 (@gcanti) 251 | 252 | # 0.3.4 253 | 254 | - **New Feature** 255 | - add `createStrMapFromDictionary` (@mlegenhausen) 256 | 257 | # 0.3.3 258 | 259 | - **New Feature** 260 | - add tagged custom types for (@gcanti, @sledorze) 261 | - createOptionFromNullable 262 | - createOptionFromJSON 263 | - createNonEmptyArrayFromArray 264 | - createEitherFromJSON 265 | - DateFromISOString 266 | - DateFromNumber 267 | - DateFromUnixTime 268 | - NumberFromString 269 | - JSONFromString 270 | - add createSetFromArray, closes #24 (@sledorze) 271 | 272 | # 0.3.2 273 | 274 | - **New Feature** 275 | - add `mapOutput`, closes #21 (@gcanti) 276 | 277 | # 0.3.1 278 | 279 | - **New Feature** 280 | - add `createNonEmptyArrayFromArray` (@sledorze) 281 | - **Bug Fix** 282 | - createOptionFromNullable: handle output type (@gcanti) 283 | 284 | # 0.3.0 285 | 286 | - **Breaking Change** 287 | - upgrade to `fp-ts@1.0.0`, `io-ts@1.0.0`, `monocle-ts@1.0.0`, `newtype-ts@0.2.0` (@gcanti) 288 | 289 | # 0.2.4 290 | 291 | - **Bug Fix** 292 | - createEitherFromJSON and createOptionFromJSON now do serialize correctly their underlying type, fix #15 (@sledorze) 293 | 294 | # 0.2.3 295 | 296 | - **New Feature** 297 | - add `MixedStringPrism` (@gcanti) 298 | - upgrade to latest `io-ts` (0.9.5) (@gcanti) 299 | 300 | # 0.2.2 301 | 302 | - **New Feature** 303 | - add `Date/DateFromUnixTime` (@gcanti) 304 | - add `monocle-ts/MillisecondSecondIso` (@gcanti) 305 | - **Internal** 306 | - upgrade to latest `io-ts@0.9.1` (@gcanti) 307 | 308 | # 0.2.1 309 | 310 | - **New Feature** 311 | - add `newtype-ts/fromNewtype`, fix #11 (@sledorze) 312 | 313 | # 0.2.0 314 | 315 | - **New Feature** 316 | - add `JSON/JSONTypeRT` (@gcanti) 317 | - add `monocle-ts/lensesFromProps` (@gcanti) 318 | - **Breaking Change** 319 | - upgrade to `io-ts` 0.9 (@gcanti) 320 | - change signature of `monocle-ts/TypePrismIso` (@gcanti) 321 | - remove `monocle-ts/composeTypeWithPrism` (@gcanti) 322 | - remove `monocle-ts/prismsFromUnion` (@gcanti) 323 | - remove `monocle-ts/lensesFromTuple` (@gcanti) 324 | - remove `fp-ts/createOption` (@gcanti) 325 | - remove `fp-ts/createEither` (@gcanti) 326 | 327 | # 0.1.1 328 | 329 | - **Breaking Change** 330 | - upgrade to fp-ts 0.6, io-ts 0.8, monocle.ts 0.5 (@gcanti) 331 | - change name from `JSON` to `JSONType` and add export, fix #8 (@gcanti) 332 | 333 | # 0.0.2 334 | 335 | - **New Feature** 336 | - add `lensesFromInterface` (@leemhenson) 337 | - add `lensesFromTuple` (@gcanti) 338 | - add `prismsFromUnion` (@gcanti) 339 | 340 | # 0.0.1 341 | 342 | Initial release 343 | --------------------------------------------------------------------------------