Skip to content

Commit

Permalink
add support for non-string tag values to sum, closes #481
Browse files Browse the repository at this point in the history
  • Loading branch information
gcanti committed Jun 16, 2020
1 parent baca458 commit 6526525
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 16 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
**Note**: Gaps between patch versions are faulty/broken releases.
**Note**: A feature tagged as Experimental is in a high state of flux, you're at risk of it changing without notice.

# 2.2.6

- **Experimental**
- `Decoder`
- add support for non-`string` tag values to `sum`, closes #481 (@gcanti)

# 2.2.5

- **Experimental**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "io-ts",
"version": "2.2.5",
"version": "2.2.6",
"description": "TypeScript runtime type system for IO decoding/encoding",
"files": [
"lib",
Expand Down
8 changes: 4 additions & 4 deletions src/Decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ export function lazy<A>(id: string, f: () => Decoder<A>): Decoder<A> {
* @since 2.2.0
*/
export function sum<T extends string>(tag: T): <A>(members: { [K in keyof A]: Decoder<A[K]> }) => Decoder<A[keyof A]> {
return (members) => {
return <A>(members: { [K in keyof A]: Decoder<A[K]> }) => {
const keys = Object.keys(members)
if (keys.length === 0) {
return never
Expand All @@ -443,9 +443,9 @@ export function sum<T extends string>(tag: T): <A>(members: { [K in keyof A]: De
if (isLeft(e)) {
return e
}
const v = e.right[tag]
if (G.string.is(v) && v in members) {
return (members as any)[v].decode(u)
const v = e.right[tag] as keyof A
if (v in members) {
return members[v].decode(u)
}
return left([
tree(`required property ${JSON.stringify(tag)}`, [
Expand Down
6 changes: 3 additions & 3 deletions src/Guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ export function union<A extends ReadonlyArray<unknown>>(...members: { [K in keyo
* @since 2.2.0
*/
export function sum<T extends string>(tag: T): <A>(members: { [K in keyof A]: Guard<A[K]> }) => Guard<A[keyof A]> {
return (members: Record<string, Guard<unknown>>) =>
return <A>(members: { [K in keyof A]: Guard<A[K]> }) =>
refinement(UnknownRecord, (r): r is any => {
const v = r[tag]
if (string.is(v) && v in members) {
const v = r[tag] as keyof A
if (v in members) {
return members[v].is(r)
}
return false
Expand Down
15 changes: 15 additions & 0 deletions test/Decoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ describe('Decoder', () => {
})
})

describe('sum', () => {
it('should support non-`string` tag values', () => {
const decoder = D.sum('_tag')({
true: D.type({ _tag: D.literal(true), a: D.string }),
false: D.type({ _tag: D.literal(false), b: D.number })
})
assert.deepStrictEqual(decoder.decode({ _tag: true, a: 'a' }), E.right({ _tag: true, a: 'a' }))
assert.deepStrictEqual(decoder.decode({ _tag: false, b: 1 }), E.right({ _tag: false, b: 1 }))
assert.deepStrictEqual(
decoder.decode({ _tag: false, b: 'a' }),
E.left([D.tree('required property "b"', [D.tree('cannot decode "a", should be number')])])
)
})
})

describe('intersect', () => {
it('should concat strings', () => {
assert.deepStrictEqual(D.intersect('a', 'b'), 'b')
Expand Down
10 changes: 10 additions & 0 deletions test/Guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,5 +230,15 @@ describe('Guard', () => {
assert.deepStrictEqual(sum({}).is(null), false)
assert.deepStrictEqual(sum({}).is({}), false)
})

it('should support non-`string` tag values', () => {
const guard = G.sum('_tag')({
true: G.type({ _tag: G.literal(true), a: G.string }),
false: G.type({ _tag: G.literal(false), b: G.number })
})
assert.deepStrictEqual(guard.is({ _tag: true, a: 'a' }), true)
assert.deepStrictEqual(guard.is({ _tag: false, b: 1 }), true)
assert.deepStrictEqual(guard.is({ _tag: false, b: 'a' }), false)
})
})
})
8 changes: 0 additions & 8 deletions test/Schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,4 @@ describe('Schema', () => {
)
check(schema)
})

// it('UnknownArray', () => {
// check(make((S) => S.UnknownArray))
// })

// it('UnknownRecord', () => {
// check(make((S) => S.UnknownRecord))
// })
})

0 comments on commit 6526525

Please sign in to comment.