Skip to content

Commit 269bd19

Browse files
feat add optional type
1 parent 9103e88 commit 269bd19

File tree

19 files changed

+234
-0
lines changed

19 files changed

+234
-0
lines changed

dtslint/ts3.5/Encoder.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ export type OfTestOutput = E.OutputOf<typeof OfTest> // $ExpectType { a: string;
2626
//
2727
E.nullable(NumberToString) // $ExpectType Encoder<string | null, number | null>
2828

29+
//
30+
// optional
31+
//
32+
E.optional(NumberToString) // $ExpectType Encoder<string | undefined, number | undefined>
33+
2934
//
3035
// struct
3136
//

dtslint/ts3.5/Schema.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ make((S) => S.boolean) // $ExpectType Schema<boolean>
5353

5454
make((S) => S.nullable(S.string)) // $ExpectType Schema<string | null>
5555

56+
//
57+
// optional
58+
//
59+
60+
make((S) => S.optional(S.string)) // $ExpectType Schema<string | undefined>
61+
5662
//
5763
// struct
5864
//

src/Codec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,14 @@ export function nullable<I, O, A>(or: Codec<I, O, A>): Codec<null | I, null | O,
142142
return make(D.nullable(or), E.nullable(or))
143143
}
144144

145+
/**
146+
* @category combinators
147+
* @since 2.3.0
148+
*/
149+
export function optional<I, O, A>(or: Codec<I, O, A>): Codec<undefined | I, undefined | O, undefined | A> {
150+
return make(D.optional(or), E.optional(or))
151+
}
152+
145153
/**
146154
* @category combinators
147155
* @since 2.2.15

src/Decoder.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,14 @@ export const nullable: <I, A>(or: Decoder<I, A>) => Decoder<null | I, null | A>
228228

229229
/**
230230
* @category combinators
231+
* @since 2.3.0
232+
*/
233+
export const optional: <I, A>(or: Decoder<I, A>) => Decoder<undefined | I, undefined | A> =
234+
/*#__PURE__*/
235+
K.optional(M)((u, e) => FS.concat(FS.of(DE.member(0, error(u, 'undefined'))), FS.of(DE.member(1, e))))
236+
237+
/**
238+
* @category combinators
231239
* @since 2.2.15
232240
*/
233241
export const fromStruct = <P extends Record<string, Decoder<any, any>>>(
@@ -488,6 +496,7 @@ export const Schemable: S.Schemable2C<URI, unknown> = {
488496
number,
489497
boolean,
490498
nullable,
499+
optional,
491500
type,
492501
struct,
493502
partial,

src/Encoder.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,16 @@ export function nullable<O, A>(or: Encoder<O, A>): Encoder<null | O, null | A> {
3939
}
4040
}
4141

42+
/**
43+
* @category combinators
44+
* @since 2.3.0
45+
*/
46+
export function optional<O, A>(or: Encoder<O, A>): Encoder<undefined | O, undefined | A> {
47+
return {
48+
encode: (a) => (a === undefined ? undefined : or.encode(a))
49+
}
50+
}
51+
4252
/**
4353
* @category combinators
4454
* @since 2.2.15

src/Eq.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ export function nullable<A>(or: Eq<A>): Eq<null | A> {
8989
}
9090
}
9191

92+
/**
93+
* @category combinators
94+
* @since 2.3.0
95+
*/
96+
export function optional<A>(or: Eq<A>): Eq<undefined | A> {
97+
return {
98+
equals: (x, y) => (x === undefined || y === undefined ? x === y : or.equals(x, y))
99+
}
100+
}
101+
92102
/**
93103
* @category combinators
94104
* @since 2.2.15
@@ -204,6 +214,7 @@ export const Schemable: Schemable1<E.URI> = {
204214
number,
205215
boolean,
206216
nullable,
217+
optional,
207218
type,
208219
struct,
209220
partial,

src/Guard.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ export const nullable = <I, A extends I>(or: Guard<I, A>): Guard<null | I, null
120120
is: (i): i is null | A => i === null || or.is(i)
121121
})
122122

123+
/**
124+
* @category combinators
125+
* @since 2.3.0
126+
*/
127+
export const optional = <I, A extends I>(or: Guard<I, A>): Guard<undefined | I, undefined | A> => ({
128+
is: (i): i is undefined | A => i === undefined || or.is(i)
129+
})
130+
123131
/**
124132
* @category combinators
125133
* @since 2.2.15
@@ -325,6 +333,7 @@ export const Schemable: S.Schemable1<URI> = {
325333
number,
326334
boolean,
327335
nullable,
336+
optional,
328337
type,
329338
struct,
330339
partial,

src/Kleisli.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,28 @@ export function nullable<M extends URIS2, E>(
123123
})
124124
}
125125

126+
/**
127+
* @category combinators
128+
* @since 2.3.0
129+
*/
130+
export function optional<M extends URIS2, E>(
131+
M: Applicative2C<M, E> & Bifunctor2<M>
132+
): <I>(
133+
onError: (i: I, e: E) => E
134+
) => <A>(or: Kleisli<M, I, E, A>) => Kleisli<M, undefined | I, E, undefined | A> {
135+
return <I>(onError: (i: I, e: E) => E) =>
136+
<A>(or: Kleisli<M, I, E, A>): Kleisli<M, undefined | I, E, undefined | A> => ({
137+
decode: (i) =>
138+
i === undefined
139+
? M.of<undefined | A>(undefined)
140+
: M.bimap(
141+
or.decode(i),
142+
(e) => onError(i, e),
143+
(a): A | undefined => a
144+
),
145+
});
146+
}
147+
126148
/**
127149
* @category combinators
128150
* @since 2.2.15

src/Schemable.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface Schemable<S> {
2828
readonly number: HKT<S, number>
2929
readonly boolean: HKT<S, boolean>
3030
readonly nullable: <A>(or: HKT<S, A>) => HKT<S, null | A>
31+
readonly optional: <A>(or: HKT<S, A>) => HKT<S, undefined | A>
3132
/** @deprecated */
3233
readonly type: <A>(properties: { [K in keyof A]: HKT<S, A[K]> }) => HKT<S, { [K in keyof A]: A[K] }>
3334
readonly struct: <A>(properties: { [K in keyof A]: HKT<S, A[K]> }) => HKT<S, { [K in keyof A]: A[K] }>
@@ -55,6 +56,7 @@ export interface Schemable1<S extends URIS> {
5556
readonly number: Kind<S, number>
5657
readonly boolean: Kind<S, boolean>
5758
readonly nullable: <A>(or: Kind<S, A>) => Kind<S, null | A>
59+
readonly optional: <A>(or: Kind<S, A>) => Kind<S, undefined | A>
5860
/** @deprecated */
5961
readonly type: <A>(properties: { [K in keyof A]: Kind<S, A[K]> }) => Kind<S, { [K in keyof A]: A[K] }>
6062
readonly struct: <A>(properties: { [K in keyof A]: Kind<S, A[K]> }) => Kind<S, { [K in keyof A]: A[K] }>
@@ -82,6 +84,7 @@ export interface Schemable2C<S extends URIS2, E> {
8284
readonly number: Kind2<S, E, number>
8385
readonly boolean: Kind2<S, E, boolean>
8486
readonly nullable: <A>(or: Kind2<S, E, A>) => Kind2<S, E, null | A>
87+
readonly optional: <A>(or: Kind2<S, E, A>) => Kind2<S, E, undefined | A>
8588
/** @deprecated */
8689
readonly type: <A>(properties: { [K in keyof A]: Kind2<S, E, A[K]> }) => Kind2<S, E, { [K in keyof A]: A[K] }>
8790
readonly struct: <A>(properties: { [K in keyof A]: Kind2<S, E, A[K]> }) => Kind2<S, E, { [K in keyof A]: A[K] }>

src/TaskDecoder.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,14 @@ export const nullable: <I, A>(or: TaskDecoder<I, A>) => TaskDecoder<null | I, nu
231231

232232
/**
233233
* @category combinators
234+
* @since 2.2.7
235+
*/
236+
export const optional: <I, A>(or: TaskDecoder<I, A>) => TaskDecoder<undefined | I, undefined | A> =
237+
/*#__PURE__*/
238+
K.optional(M)((u, e) => FS.concat(FS.of(DE.member(0, error(u, 'undefined'))), FS.of(DE.member(1, e))))
239+
240+
/**
241+
* @category combinators
234242
* @since 2.2.15
235243
*/
236244
export const fromStruct = <P extends Record<string, TaskDecoder<any, any>>>(
@@ -494,6 +502,7 @@ export const Schemable: S.Schemable2C<URI, unknown> = {
494502
number,
495503
boolean,
496504
nullable,
505+
optional,
497506
type,
498507
struct,
499508
partial,

0 commit comments

Comments
 (0)