Skip to content

Commit 9585e0b

Browse files
fix(maybe): correct typings using NonNullable<T> (#21)
1 parent 0cd967c commit 9585e0b

File tree

4 files changed

+64
-39
lines changed

4 files changed

+64
-39
lines changed

src/interfaces/maybe.interface.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export interface IMaybePattern<TIn, TOut> {
77
/**
88
* Function to handle when a value exists.
99
*/
10-
some(val: TIn): TOut
10+
some(val: NonNullable<TIn>): TOut
1111

1212
/**
1313
* Function to handle when a value is undefined.
@@ -22,12 +22,12 @@ export interface IMaybe<T> extends IMonad<T> {
2222
/**
2323
* Unwrap a Maybe with a default value
2424
*/
25-
valueOr(val: T): T
25+
valueOr(val: NonNullable<T>): NonNullable<T>
2626

2727
/**
2828
* Unwrap a Maybe with a default computed value
2929
*/
30-
valueOrCompute(f: () => T): T
30+
valueOrCompute(f: () => NonNullable<T>): NonNullable<T>
3131

3232
/**
3333
* Execute functions with side-effects.
@@ -42,7 +42,7 @@ export interface IMaybe<T> extends IMonad<T> {
4242
/**
4343
* Execute a function with side-effects when maybe is a some.
4444
*/
45-
tapSome(f: (val: T) => void): void
45+
tapSome(f: (val: NonNullable<T>) => void): void
4646

4747
/**
4848
* Unwrap and apply MaybePattern functions
@@ -52,12 +52,12 @@ export interface IMaybe<T> extends IMonad<T> {
5252
/**
5353
* Combine multiple maybe
5454
*/
55-
map<R>(f: (t: T) => R): IMaybe<R>
55+
map<R>(f: (t: NonNullable<T>) => R): IMaybe<R>
5656

5757
/**
5858
* Combine multiple maybe
5959
*/
60-
flatMap<R>(f: (t: T) => IMaybe<R>): IMaybe<R>
60+
flatMap<R>(f: (t: NonNullable<T>) => IMaybe<R>): IMaybe<R>
6161

6262
// tslint:disable-next-line:readonly-array
6363
of(x?: T, ...args: any[]): IMaybe<T>

src/monads/maybe.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ import { IMaybe, IMaybePattern } from "../interfaces"
33
export function maybe<T>(value?: T): IMaybe<T> {
44
return {
55
of: (x) => maybe(x),
6-
valueOr: (val: T) => value === null || value === undefined ? val : value,
7-
valueOrCompute: (f: () => T) => value === null || value === undefined ? f() : value,
8-
tap: (obj: Partial<IMaybePattern<T, void>>) => value === null || value === undefined ? obj.none && obj.none() : obj.some && obj.some(value),
6+
valueOr: (val: NonNullable<T>) => value === null || value === undefined ? val : value as NonNullable<T>,
7+
valueOrCompute: (f: () => NonNullable<T>) => value === null || value === undefined ? f() : value as NonNullable<T>,
8+
tap: (obj: Partial<IMaybePattern<T, void>>) => value === null || value === undefined ? obj.none && obj.none() : obj.some && obj.some(value as NonNullable<T>),
99
tapNone: (f: () => void) => (value === null || value === undefined) && f(),
10-
tapSome: (f: (val: T) => void) => value !== null && value !== undefined && f(value),
11-
match: <R>(pattern: IMaybePattern<T, R>) => value === null || value === undefined ? pattern.none() : pattern.some(value),
12-
map: <R>(f: (t: T) => R) => value === null || value === undefined ? maybe<R>() : maybe<R>(f(value)),
13-
flatMap: <R>(f: (d: T) => IMaybe<R>) => value === null || value === undefined ? maybe<R>() : f(value)
10+
tapSome: (f: (val: NonNullable<T>) => void) => value !== null && value !== undefined && f(value as NonNullable<T>),
11+
match: <R>(pattern: IMaybePattern<T, R>) => value === null || value === undefined ? pattern.none() : pattern.some(value as NonNullable<T>),
12+
map: <R>(f: (t: NonNullable<T>) => R) => value === null || value === undefined ? maybe<R>() : maybe<R>(f(value as NonNullable<T>)),
13+
flatMap: <R>(f: (d: NonNullable<T>) => IMaybe<R>) => value === null || value === undefined ? maybe<R>() : f(value as NonNullable<T>)
1414
}
1515
}

test/monads/maybe.spec.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,35 @@ import { maybe } from "../../src"
33
describe('Maybe', () => {
44
describe('when returning a value by default', () => {
55
it('should handle "none" case', () => {
6-
const sut: string | undefined = undefined
6+
const sut = undefined as string | undefined
77
const maybeAString = maybe(sut).valueOr('default output')
88

99
expect(maybeAString).toEqual('default output')
1010
})
1111

1212
it('should handle "some" case', () => {
13-
const sut: string | undefined = 'actual input'
13+
const sut = 'actual input' as string | undefined
1414
const maybeAString = maybe(sut).valueOr('default output')
1515

1616
expect(maybeAString).toEqual('actual input')
1717
})
1818

1919
it('should handle "some" case when input is null', () => {
20-
const sut: string | undefined | null = null
20+
const sut = null as string | undefined | null
2121
const maybeAString = maybe(sut).valueOr('default output')
2222

2323
expect(maybeAString).toEqual('default output')
2424
})
2525

2626
it('should handle "some" case when input is ""', () => {
27-
const sut: string | undefined | null = ''
27+
const sut = '' as string | undefined | null
2828
const maybeAString = maybe(sut).valueOr('fallback')
2929

3030
expect(maybeAString).toEqual('')
3131
})
3232

3333
it('should handle "some" case when input is 0', () => {
34-
const sut: number | undefined | null = 0
34+
const sut = 0 as number | undefined | null
3535
const maybeAString = maybe(sut).valueOr(10)
3636

3737
expect(maybeAString).toEqual(0)
@@ -40,7 +40,7 @@ describe('Maybe', () => {
4040

4141
describe('when returning a value by computation', () => {
4242
it('should handle "none" case', () => {
43-
const sut: string | undefined = undefined
43+
const sut = undefined as string | undefined
4444
const maybeAString = maybe(sut).valueOrCompute(() => 'default output')
4545

4646
expect(maybeAString).toEqual('default output')
@@ -54,21 +54,21 @@ describe('Maybe', () => {
5454
})
5555

5656
it('should handle "some" case when input is null', () => {
57-
const sut: string | undefined = null
57+
const sut = null as string | null
5858
const maybeAString = maybe(sut).valueOrCompute(() => 'fallback')
5959

6060
expect(maybeAString).toEqual('fallback')
6161
})
6262

6363
it('should handle "some" case when input is ""', () => {
64-
const sut: string | undefined = ''
64+
const sut = '' as string | undefined
6565
const maybeAString = maybe(sut).valueOrCompute(() => 'fallback')
6666

6767
expect(maybeAString).toEqual('')
6868
})
6969

7070
it('should handle "some" case when input is 0', () => {
71-
const sut: number | undefined = 0
71+
const sut = 0 as number | undefined
7272
const maybeAString = maybe(sut).valueOrCompute(() => 10)
7373

7474
expect(maybeAString).toEqual(0)
@@ -77,7 +77,7 @@ describe('Maybe', () => {
7777

7878
describe('when returning from a match operation', () => {
7979
it('should handle "none" case', () => {
80-
const sut: string | undefined = undefined
80+
const sut = undefined as string | undefined
8181
const maybeAMappedString = maybe(sut)
8282
.match({
8383
none: () => 'fallback',
@@ -88,7 +88,7 @@ describe('Maybe', () => {
8888
})
8989

9090
it('should handle "some" case', () => {
91-
const sut: string | undefined = 'existing value'
91+
const sut = 'existing value' as string | undefined
9292
const maybeAMappedString = maybe(sut)
9393
.match({
9494
none: () => 'fallback',
@@ -102,8 +102,8 @@ describe('Maybe', () => {
102102
describe('when performing side-effect operations', () => {
103103
it('should handle "none" case', () => {
104104
// tslint:disable-next-line:no-let
105-
let sideEffectStore: string
106-
const sut: string | undefined = undefined
105+
let sideEffectStore = ''
106+
const sut = undefined as string | undefined
107107

108108
maybe(sut)
109109
.tap({
@@ -118,8 +118,8 @@ describe('Maybe', () => {
118118

119119
it('should handle "some" case', () => {
120120
// tslint:disable-next-line:no-let
121-
let sideEffectStore: string
122-
const sut: string | undefined = 'existing value'
121+
let sideEffectStore = ''
122+
const sut = 'existing value' as string | undefined
123123

124124
maybe(sut)
125125
.tap({
@@ -139,7 +139,7 @@ describe('Maybe', () => {
139139
}
140140

141141
it('should handle valid input', () => {
142-
const sut: string | undefined = 'initial input'
142+
const sut = 'initial input' as string | undefined
143143

144144
const maybeSomeString = maybe(sut)
145145
.map(_str => getUserService<string>('initial input mapped'))
@@ -163,7 +163,7 @@ describe('Maybe', () => {
163163
})
164164

165165
it('should handle undefined input', () => {
166-
const sut: string | undefined = undefined
166+
const sut = undefined as string | undefined
167167

168168
const maybeSomeString = maybe(sut)
169169
.map(_str => getUserService<string>('initial input mapped'))
@@ -187,7 +187,7 @@ describe('Maybe', () => {
187187
})
188188

189189
it('should handle input of 0', () => {
190-
const sut: number | undefined = 0
190+
const sut = 0 as number | undefined
191191

192192
const maybeSomeString = maybe(sut)
193193
.map(_str => getUserService<string>('initial input mapped'))
@@ -211,7 +211,7 @@ describe('Maybe', () => {
211211
})
212212

213213
it('should handle input of ""', () => {
214-
const sut: string | undefined = ''
214+
const sut = '' as string | undefined
215215

216216
const maybeSomeString = maybe(sut)
217217
.map(_str => getUserService<string>('initial input mapped'))
@@ -237,8 +237,8 @@ describe('Maybe', () => {
237237

238238
describe('when flatMapping', () => {
239239
it('should handle "none" case', () => {
240-
const sut: string | undefined = undefined
241-
const nsut: number | undefined = undefined
240+
const sut = undefined as string | undefined
241+
const nsut = undefined as number | undefined
242242

243243
const maybeSomeNumber = maybe(sut)
244244
.flatMap(() => maybe(nsut))
@@ -248,8 +248,8 @@ describe('Maybe', () => {
248248
})
249249

250250
it('should handle "some" case', () => {
251-
const sut: string | undefined = 'initial'
252-
const nsut: number | undefined = 20
251+
const sut = 'initial' as string | undefined
252+
const nsut = 20 as number | undefined
253253

254254
const maybeSomeNumber = maybe(sut)
255255
.flatMap(() => maybe(nsut))
@@ -261,7 +261,7 @@ describe('Maybe', () => {
261261

262262
describe('when getting monadic unit', () => {
263263
it('should get value', () => {
264-
const sut: string | undefined = undefined
264+
const sut = undefined as string | undefined
265265

266266
const maybeSomeNumber = maybe(sut)
267267
.of('ok')
@@ -273,7 +273,7 @@ describe('Maybe', () => {
273273

274274
describe('when tapSome', () => {
275275
it('should work', () => {
276-
const sut: string | undefined = 'abc'
276+
const sut = 'abc' as string | undefined
277277

278278
expect.assertions(1)
279279
maybe(sut).tapSome(a => expect(a).toEqual('abc'))
@@ -283,7 +283,7 @@ describe('Maybe', () => {
283283

284284
describe('when tapNone', () => {
285285
it('should work', () => {
286-
const sut: string | undefined = undefined
286+
const sut = undefined as string | undefined
287287

288288
expect.assertions(1)
289289
maybe(sut).tapNone(() => expect(1).toEqual(1))

test/tsconfig.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es5",
4+
"module": "commonjs",
5+
"moduleResolution": "node",
6+
"lib": ["es2015", "dom"],
7+
"isolatedModules": false,
8+
"experimentalDecorators": true,
9+
"emitDecoratorMetadata": true,
10+
"noImplicitAny": true,
11+
"noImplicitUseStrict": false,
12+
"noEmitHelpers": false,
13+
"noEmit": true,
14+
"noLib": false,
15+
"noUnusedLocals": true,
16+
"noEmitOnError": true,
17+
"allowSyntheticDefaultImports": false,
18+
"skipLibCheck": true,
19+
"skipDefaultLibCheck": true,
20+
"strict": true,
21+
"strictNullChecks": true,
22+
"strictFunctionTypes": true,
23+
"forceConsistentCasingInFileNames": true
24+
}
25+
}

0 commit comments

Comments
 (0)