Skip to content

Commit

Permalink
remove NaN from number instances
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti committed Jun 29, 2020
1 parent b1b704e commit ac43c19
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 27 deletions.
25 changes: 13 additions & 12 deletions CHANGELOG.md
Expand Up @@ -23,22 +23,23 @@
- add `Kleisli` module (@gcanti)
- add `KleisliDecoder` module (@gcanti)
- add `KleisliTaskDecoder` module (@gcanti)
- (**bc**) remove `Tree` module (@gcanti)
- (**bc**) make `Json` type immutable (@gcanti)
- (\*) remove `NaN` from `number` instances (@gcanti)
- (\*) remove `Tree` module (@gcanti)
- (\*) make `Json` type immutable (@gcanti)
- `Decoder`
- (**bc**) remove `never` (@gcanti)
- (**bc**) make `parse` pipeable and change its `parser` argument (@gcanti)
- (**bc**) change `DecoderError` (@gcanti)
- (**bc**) remove `withExpected` in favour of `mapLeftWithInput` (@gcanti)
- (\*) remove `never` (@gcanti)
- (\*) make `parse` pipeable and change its `parser` argument (@gcanti)
- (\*) change `DecoderError` (@gcanti)
- (\*) remove `withExpected` in favour of `mapLeftWithInput` (@gcanti)
- `Guard`
- (**bc**) remove `never` (@gcanti)
- (\*) remove `never` (@gcanti)
- `Schemable`
- (**bc**) better `literal` signature (@gcanti)
- (**bc**) better `union` signature (@gcanti)
- (**bc**) make intersections pipeables (@gcanti)
- (**bc**) make refinements pipeables (@gcanti)
- (\*) better `literal` signature (@gcanti)
- (\*) better `union` signature (@gcanti)
- (\*) make intersections pipeables (@gcanti)
- (\*) make refinements pipeables (@gcanti)

**bc** means "breaking change"
(\*) breaking change

# 2.2.6

Expand Down
2 changes: 2 additions & 0 deletions docs/modules/Guard.ts.md
Expand Up @@ -256,6 +256,8 @@ Added in v2.2.0

## number

Note: `NaN` is excluded.

**Signature**

```ts
Expand Down
4 changes: 3 additions & 1 deletion src/Guard.ts
Expand Up @@ -50,11 +50,13 @@ export const string: Guard<string> = {
}

/**
* Note: `NaN` is excluded.
*
* @category primitives
* @since 2.2.0
*/
export const number: Guard<number> = {
is: (u: unknown): u is number => typeof u === 'number'
is: (u: unknown): u is number => typeof u === 'number' && !isNaN(u)
}

/**
Expand Down
13 changes: 12 additions & 1 deletion src/Type.ts
Expand Up @@ -3,6 +3,8 @@
*/
import * as t from './index'
import { Literal, Schemable1, WithUnion1, WithRefine1, WithUnknownContainers1 } from './Schemable'
import * as E from 'fp-ts/lib/Either'
import { pipe } from 'fp-ts/lib/pipeable'

// -------------------------------------------------------------------------------------
// model
Expand Down Expand Up @@ -39,7 +41,16 @@ export const string: Type<string> = t.string
* @category primitives
* @since 2.2.3
*/
export const number: Type<number> = t.number
export const number: Type<number> = new t.Type(
t.number.name,
t.number.is,
(u, c) =>
pipe(
t.number.decode(u),
E.chain((n) => (isNaN(n) ? t.failure(u, c) : t.success(n)))
),
t.number.encode
)

/**
* @category primitives
Expand Down
12 changes: 9 additions & 3 deletions test/Decoder.ts
Expand Up @@ -63,9 +63,15 @@ describe('Decoder', () => {
assert.deepStrictEqual(_.string.decode(null), E.left(FS.of(DE.leaf(null, 'string'))))
})

it('number', async () => {
assert.deepStrictEqual(_.number.decode(1), _.success(1))
assert.deepStrictEqual(_.number.decode(null), E.left(FS.of(DE.leaf(null, 'number'))))
describe('number', () => {
it('number', async () => {
assert.deepStrictEqual(_.number.decode(1), _.success(1))
assert.deepStrictEqual(_.number.decode(null), E.left(FS.of(DE.leaf(null, 'number'))))
})

it('should exclude NaN', () => {
assert.deepStrictEqual(_.number.decode(NaN), E.left(FS.of(DE.leaf(NaN, 'number'))))
})
})

it('boolean', async () => {
Expand Down
6 changes: 6 additions & 0 deletions test/Guard.ts
Expand Up @@ -3,6 +3,12 @@ import * as G from '../src/Guard'
import { pipe } from 'fp-ts/lib/pipeable'

describe('Guard', () => {
describe('number', () => {
it('should exclude NaN', () => {
assert.deepStrictEqual(G.number.is(NaN), false)
})
})

describe('refine', () => {
it('should accepts valid inputs', () => {
const guard = pipe(
Expand Down
26 changes: 16 additions & 10 deletions test/Type.ts
@@ -1,6 +1,6 @@
import * as assert from 'assert'
import * as fc from 'fast-check'
import { isRight } from 'fp-ts/lib/Either'
import { isRight, isLeft } from 'fp-ts/lib/Either'
import { Kind, URIS, HKT } from 'fp-ts/lib/HKT'
import * as t from '../src'
import * as D from '../src/Decoder'
Expand All @@ -14,7 +14,7 @@ import {
WithUnknownContainers,
WithUnknownContainers1
} from '../src/Schemable'
import * as T from '../src/Type'
import * as _ from '../src/Type'
import * as A from './Arbitrary'
import { pipe } from 'fp-ts/lib/pipeable'

Expand All @@ -36,7 +36,7 @@ function check<A>(schema: Schema<A>, type: t.Type<A>): void {
const arb = interpreter(A.schemableArbitrary)(schema)
const decoder = interpreter(D.schemableDecoder)(schema)
const guard = interpreter(G.schemableGuard)(schema)
const itype = interpreter(T.schemableType)(schema)
const itype = interpreter(_.schemableType)(schema)
// decoder and type should be aligned
fc.assert(fc.property(arb, (a) => isRight(decoder.decode(a)) === isRight(type.decode(a))))
// interpreted type and type should be aligned
Expand All @@ -53,11 +53,17 @@ describe('Type', () => {
)
})

it('number', () => {
check(
make((S) => S.number),
t.number
)
describe('number', () => {
it('number', () => {
check(
make((S) => S.number),
t.number
)
})

it('should exclude NaN', () => {
assert.deepStrictEqual(isLeft(_.number.decode(NaN)), true)
})
})

it('boolean', () => {
Expand Down Expand Up @@ -198,8 +204,8 @@ describe('Type', () => {
}
type NonEmptyString = string & NonEmptyStringBrand
const type = pipe(
T.string,
T.refine((s): s is NonEmptyString => s.length > 0, 'NonEmptyString')
_.string,
_.refine((s): s is NonEmptyString => s.length > 0, 'NonEmptyString')
)
assert.deepStrictEqual(isRight(type.decode('a')), true)
assert.deepStrictEqual(isRight(type.decode('')), false)
Expand Down

0 comments on commit ac43c19

Please sign in to comment.