>>
+ >
+>
```
Added in v2.2.7
diff --git a/docs/modules/Encoder.ts.md b/docs/modules/Encoder.ts.md
index 153decb6..8208a586 100644
--- a/docs/modules/Encoder.ts.md
+++ b/docs/modules/Encoder.ts.md
@@ -167,7 +167,7 @@ Added in v2.2.3
```ts
export declare function struct>>(
properties: P
-): Encoder<{ [K in keyof P]: OutputOf
}, { [K in keyof P]: TypeOf
}>
+): Encoder }>, { [K in keyof P]: TypeOf }>
```
Added in v2.2.15
diff --git a/dtslint/ts3.5/Codec.ts b/dtslint/ts3.5/Codec.ts
index 677e7fe0..257a183e 100644
--- a/dtslint/ts3.5/Codec.ts
+++ b/dtslint/ts3.5/Codec.ts
@@ -1,12 +1,14 @@
import * as _ from '../../src/Codec'
+declare const Optional: (codec: _.Codec) => _.Codec
+
declare const NumberFromString: _.Codec
//
// fromStruct
//
-// $ExpectType Codec<{ a: unknown; b: { c: string; }; }, { a: string; b: { c: string; }; }, { a: string; b: { c: number; }; }>
+// $ExpectType Codec<{ b: { c: string; }; a?: unknown; }, { a: string; b: { c: string; }; }, { a: string; b: { c: number; }; }>
_.fromStruct({
a: _.string,
b: _.fromStruct({
@@ -14,6 +16,14 @@ _.fromStruct({
})
})
+// $ExpectType Codec<{ b: { c?: string | undefined; }; a?: unknown; }, { b: { c?: string | undefined; }; a?: string | undefined; }, { b: { c?: number | undefined; }; a?: string | undefined; }>
+_.fromStruct({
+ a: Optional(_.string),
+ b: _.fromStruct({
+ c: Optional(NumberFromString)
+ })
+})
+
//
// struct
//
@@ -26,6 +36,14 @@ _.struct({
})
})
+// $ExpectType Codec
+_.struct({
+ a: Optional(_.string),
+ b: _.struct({
+ c: Optional(_.number),
+ }),
+})
+
//
// fromPartial
//
@@ -96,7 +114,7 @@ _.tuple(_.string, _.number, _.boolean)
// fromSum
//
-// $ExpectType Codec<{ _tag: unknown; a: unknown; } | { _tag: unknown; b: string; }, { _tag: "A"; a: string; } | { _tag: "B"; b: string; }, { _tag: "A"; a: string; } | { _tag: "B"; b: number; }>
+// $ExpectType Codec<{ a?: unknown; _tag?: unknown; } | { b: string; _tag?: unknown; }, { a: string; _tag: "A"; } | { b: string; _tag: "B"; }, { a: string; _tag: "A"; } | { b: number; _tag: "B"; }>
_.fromSum('_tag')({
A: _.fromStruct({ _tag: _.literal('A'), a: _.string }),
B: _.fromStruct({ _tag: _.literal('B'), b: NumberFromString })
@@ -109,7 +127,7 @@ _.fromSum('_tag')({
const S1 = _.struct({ _tag: _.literal('A'), a: _.string })
const S2 = _.struct({ _tag: _.literal('B'), b: _.number })
-// $ExpectType Codec
+// $ExpectType Codec
_.sum('_tag')({ A: S1, B: S2 })
// // $ExpectError
// _.sum('_tag')({ A: S1, B: S1 })
diff --git a/dtslint/ts3.5/Decoder.ts b/dtslint/ts3.5/Decoder.ts
index 94e80ca7..fd2d03ca 100644
--- a/dtslint/ts3.5/Decoder.ts
+++ b/dtslint/ts3.5/Decoder.ts
@@ -3,6 +3,8 @@ import * as DE from '../../src/DecodeError'
import * as _ from '../../src/Decoder'
import * as FS from '../../src/FreeSemigroup'
+declare const Optional: (decoder: _.Decoder) => _.Decoder
+
declare const NumberFromString: _.Decoder
//
@@ -43,6 +45,14 @@ _.struct({
})
})
+// $ExpectType Decoder
+_.struct({
+ a: Optional(_.string),
+ b: _.struct({
+ c: Optional(_.number)
+ })
+})
+
//
// fromPartial
//
@@ -113,7 +123,7 @@ _.tuple(_.string, _.number, _.boolean)
// fromSum
//
-// $ExpectType Decoder<{ _tag: unknown; a: unknown; } | { _tag: unknown; b: string; }, { _tag: "A"; a: string; } | { _tag: "B"; b: number; }>
+// $ExpectType Decoder<{ _tag: unknown; a: unknown; } | { _tag: unknown; b: string; }, { a: string; _tag: "A"; } | { b: number; _tag: "B"; }>
_.fromSum('_tag')({
A: _.fromStruct({ _tag: _.literal('A'), a: _.string }),
B: _.fromStruct({ _tag: _.literal('B'), b: NumberFromString })
@@ -126,7 +136,7 @@ _.fromSum('_tag')({
const S1 = _.struct({ _tag: _.literal('A'), a: _.string })
const S2 = _.struct({ _tag: _.literal('B'), b: _.number })
-// $ExpectType Decoder
+// $ExpectType Decoder
_.sum('_tag')({ A: S1, B: S2 })
// $ExpectError
_.sum('_tag')({ A: S1, B: S1 })
diff --git a/dtslint/ts3.5/Encoder.ts b/dtslint/ts3.5/Encoder.ts
index 8bb901d4..327aae9f 100644
--- a/dtslint/ts3.5/Encoder.ts
+++ b/dtslint/ts3.5/Encoder.ts
@@ -1,6 +1,8 @@
import * as E from '../../src/Encoder'
import { pipe } from 'fp-ts/lib/pipeable'
+declare const Optional: (encoder: E.Encoder) => E.Encoder
+
const NumberToString: E.Encoder = {
encode: String
}
@@ -30,6 +32,7 @@ E.nullable(NumberToString) // $ExpectType Encoder
// struct
//
E.struct({ a: E.struct({ b: NumberToString }) }) // $ExpectType Encoder<{ a: { b: string; }; }, { a: { b: number; }; }>
+E.struct({ a: Optional(E.struct({ b: Optional(NumberToString) })) }) // $ExpectType Encoder<{ a?: { b?: string | undefined; } | undefined; }, { a: { b: number | undefined; } | undefined; }>
//
// partial
@@ -65,7 +68,7 @@ const S1 = E.struct({ _tag: E.id<'A'>(), a: NumberToString })
const S2 = E.struct({ _tag: E.id<'B'>(), b: BooleanToNumber })
const sum = E.sum('_tag')
-// $ExpectType Encoder<{ _tag: "A"; a: string; } | { _tag: "B"; b: number; }, { _tag: "A"; a: number; } | { _tag: "B"; b: boolean; }>
+// $ExpectType Encoder<{ a: string; _tag: "A"; } | { b: number; _tag: "B"; }, { _tag: "A"; a: number; } | { _tag: "B"; b: boolean; }>
sum({ A: S1, B: S2 })
const S3 = E.struct({ _tag: E.id<'C'>(), c: E.id() })
diff --git a/src/Codec.ts b/src/Codec.ts
index fe43c2aa..bcc1da6b 100644
--- a/src/Codec.ts
+++ b/src/Codec.ts
@@ -148,8 +148,12 @@ export function nullable(or: Codec): Codec>>(
properties: P
-): Codec<{ [K in keyof P]: InputOf }, { [K in keyof P]: OutputOf
}, { [K in keyof P]: TypeOf
}> {
- return make(D.fromStruct(properties) as any, E.struct(properties))
+): Codec<
+ ToOptional<{ [K in keyof P]: InputOf
}>,
+ ToOptional<{ [K in keyof P]: OutputOf
}>,
+ ToOptional<{ [K in keyof P]: TypeOf
}>
+> {
+ return make(D.fromStruct(properties) as any, E.struct(properties) as any)
}
/**
@@ -167,7 +171,7 @@ export const fromType = fromStruct
*/
export function struct
>>(
properties: P
-): Codec }, { [K in keyof P]: TypeOf }> {
+): Codec }>, ToOptional<{ [K in keyof P]: TypeOf }>> {
return pipe(UnknownRecord, compose(fromStruct(properties as any))) as any
}
@@ -385,3 +389,10 @@ export type OutputOf = E.OutputOf
* @since 2.2.3
*/
export type TypeOf = E.TypeOf
+
+type UndefinedProperties = {
+ [P in keyof T]-?: undefined extends T[P] ? P : never
+}[keyof T]
+type ToOptional = Merge>> & Partial>>>
+type Identity = T
+type Merge = T extends any ? Identity<{ [k in keyof T]: T[k] }> : never
diff --git a/src/Decoder.ts b/src/Decoder.ts
index f98ff1d2..7751774b 100644
--- a/src/Decoder.ts
+++ b/src/Decoder.ts
@@ -232,8 +232,8 @@ export const nullable: (or: Decoder) => Decoder
*/
export const fromStruct = >>(
properties: P
-): Decoder<{ [K in keyof P]: InputOf
}, { [K in keyof P]: TypeOf
}> =>
- K.fromStruct(M)((k, e) => FS.of(DE.key(k, DE.required, e)))(properties)
+): Decoder<{ [K in keyof P]: InputOf
}, ToOptional<{ [K in keyof P]: TypeOf
}>> =>
+ K.fromStruct(M)((k, e) => FS.of(DE.key(k, DE.required, e)))(properties) as any
/**
* Use `fromStruct` instead.
@@ -250,7 +250,8 @@ export const fromType = fromStruct
*/
export const struct = (
properties: { [K in keyof A]: Decoder }
-): Decoder => pipe(UnknownRecord as any, compose(fromStruct(properties)))
+): Decoder> =>
+ pipe(UnknownRecord as any, compose(fromStruct(properties))) as any
/**
* Use `struct` instead.
@@ -488,8 +489,8 @@ export const Schemable: S.Schemable2C = {
number,
boolean,
nullable,
- type,
- struct,
+ type: type as S.Schemable2C['type'], // tslint:disable-line:deprecation
+ struct: struct as S.Schemable2C['struct'],
partial,
record,
array,
@@ -609,3 +610,10 @@ export const draw = (e: DecodeError): string => toForest(e).map(drawTree).join('
export const stringify: (e: E.Either) => string =
/*#__PURE__*/
E.fold(draw, (a) => JSON.stringify(a, null, 2))
+
+type UndefinedProperties = {
+ [P in keyof T]-?: undefined extends T[P] ? P : never
+}[keyof T]
+type ToOptional = Merge>> & Partial>>>
+type Identity = T
+type Merge = T extends any ? Identity<{ [k in keyof T]: T[k] }> : never
diff --git a/src/Encoder.ts b/src/Encoder.ts
index 8cf7a085..b28cb9de 100644
--- a/src/Encoder.ts
+++ b/src/Encoder.ts
@@ -45,14 +45,14 @@ export function nullable(or: Encoder): Encoder {
*/
export function struct>>(
properties: P
-): Encoder<{ [K in keyof P]: OutputOf
}, { [K in keyof P]: TypeOf
}> {
+): Encoder }>, { [K in keyof P]: TypeOf }> {
return {
encode: (a) => {
const o: Record = {} as any
for (const k in properties) {
o[k] = properties[k].encode(a[k])
}
- return o
+ return o as any
}
}
}
@@ -260,3 +260,10 @@ export type TypeOf = E extends Encoder ? A : never
* @since 2.2.3
*/
export type OutputOf = E extends Encoder ? O : never
+
+type UndefinedProperties = {
+ [P in keyof T]-?: undefined extends T[P] ? P : never
+}[keyof T]
+type ToOptional = Merge>> & Partial>>>
+type Identity = T
+type Merge = T extends any ? Identity<{ [k in keyof T]: T[k] }> : never