Repository: gcanti/io-ts-types (ts)

Issue:
Relax fromNewtype signature
```ts
interface Id extends Newtype<'Id', string> {}

const Id = fromNewtype<Id>(t.string)

interface User {
  id: Id
  name: string
}

const User = t.interface({
  id: Id,
  name: t.string
})

interface SpecialUser extends Newtype<'SpecialUser', User> {}

const SpecialUser = fromNewtype<SpecialUser>(User) // static error: Type 'string' is not assignable to type 'Id'
```

This is due to `O` being restricted to `CarrierOf<N>`

```ts
export const fromNewtype: <N extends AnyNewtype>(
  type: Type<CarrierOf<N>, CarrierOf<N>, mixed>
) => Type<N, CarrierOf<N>, mixed> = type => type as any
```

Proposed solution: add a `fromNewtypeCurried` function when `O` is free

```ts
export const fromNewtypeCurried = <N extends AnyNewtype = never>() => <O>(
  type: Type<CarrierOf<N>, O, mixed>
): Type<N, O, mixed> => type as any
```

Pull request description:
New Feature: add newtype-ts/fromNewtypeCurried, closes #44

Patch:
diff --git a/src/index.ts b/src/index.ts
index 22ef348..5200cc7 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -23,6 +23,7 @@ export { TypePrismIso }
 
 // newtype-ts
 export { fromNewtype } from './newtype-ts/fromNewtype'
+export { fromNewtypeCurried } from './newtype-ts/fromNewtype'
 export { fromRefinement } from './newtype-ts/fromRefinement'
 
 // number
diff --git a/src/newtype-ts/fromNewtype.ts b/src/newtype-ts/fromNewtype.ts
index 5365cff..5a26b52 100644
--- a/src/newtype-ts/fromNewtype.ts
+++ b/src/newtype-ts/fromNewtype.ts
@@ -1,6 +1,10 @@
 import { AnyNewtype, CarrierOf } from 'newtype-ts'
 import { Type, mixed } from 'io-ts'
 
-export const fromNewtype: <N extends AnyNewtype>(
+export const fromNewtype: <N extends AnyNewtype = never>(
   type: Type<CarrierOf<N>, CarrierOf<N>, mixed>
 ) => Type<N, CarrierOf<N>, mixed> = type => type as any
+
+export const fromNewtypeCurried = <N extends AnyNewtype = never>() => <O>(
+  type: Type<CarrierOf<N>, O, mixed>
+): Type<N, O, mixed> => type as any


Test patch:
diff --git a/test/index.ts b/test/index.ts
index 65c6be5..dc0e5ed 100644
--- a/test/index.ts
+++ b/test/index.ts
@@ -22,13 +22,13 @@ import {
   fromRefinement,
   lensesFromProps,
   lensesFromInterface,
-  mapOutput
+  mapOutput,
+  fromNewtypeCurried
 } from '../src'
 import { left, right } from 'fp-ts/lib/Either'
 import { none, some } from 'fp-ts/lib/Option'
 
 import { Newtype } from 'newtype-ts'
-import { Validation } from 'io-ts'
 import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
 import { ordNumber } from 'fp-ts/lib/Ord'
 import { StrMap } from 'fp-ts/lib/StrMap'
@@ -254,13 +254,39 @@ describe('monocle-ts', () => {
 
 describe('newtype-ts', () => {
   it('fromNewtype', () => {
-    type Age = Newtype<'Age', number>
+    interface Age extends Newtype<'Age', number> {}
     const isoAge = iso<Age>()
     const T = fromNewtype<Age>(t.number)
-    const res: Validation<Age> = T.decode(42)
-    assert.deepEqual(res, right(42))
-    const e: number = T.encode(isoAge.wrap(42))
-    assert.strictEqual(e, 42)
+    assert.deepEqual(T.decode(42), right(42))
+    assert.strictEqual(T.encode(isoAge.wrap(42)), 42)
+  })
+
+  it('fromNewtypeCurried', () => {
+    interface Id extends Newtype<'Id', string> {}
+
+    const Id = fromNewtype<Id>(t.string)
+    const isoId = iso<Id>()
+
+    interface User {
+      id: Id
+      name: string
+    }
+
+    const User = t.interface({
+      id: Id,
+      name: t.string
+    })
+
+    interface SpecialUser extends Newtype<'SpecialUser', User> {}
+
+    const isoSpecialUser = iso<SpecialUser>()
+
+    const T = fromNewtypeCurried<SpecialUser>()(User)
+    assert.deepEqual(T.decode({ id: 'abc', name: 'name' }), right({ id: 'abc', name: 'name' }))
+    assert.deepEqual(T.encode(isoSpecialUser.wrap({ id: isoId.wrap('abc'), name: 'name' })), {
+      id: 'abc',
+      name: 'name'
+    })
   })
 
   it('fromRefinement', () => {