Skip to content

Commit

Permalink
✨ Add ifElseFn and change ifElse function
Browse files Browse the repository at this point in the history
  • Loading branch information
TomokiMiyauci committed May 9, 2021
1 parent 9754460 commit a13525b
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 67 deletions.
7 changes: 3 additions & 4 deletions api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,10 @@ const api: Api = {
lodash: 'findIndex',
fonction: undefined
},

ifElse: {
ifElse: {},
ifElseFn: {
ramda: 'ifElse',
rambda: 'ifElse',
fonction: undefined
rambda: 'ifElse'
},
includes: {
ramda: 'includes',
Expand Down
1 change: 1 addition & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export { hasPath } from './src/hasPath.ts'
export { head } from './src/head.ts'
export { identity } from './src/identity.ts'
export { ifElse } from './src/ifElse.ts'
export { ifElseFn } from './src/ifElseFn.ts'
export { inc } from './src/inc.ts'
export { isArray } from './src/isArray.ts'
export { isBigint } from './src/isBigint.ts'
Expand Down
48 changes: 22 additions & 26 deletions src/ifElse.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
// Copyright 2021-present the Fonction authors. All rights reserved. MIT license.
import { isFunction } from './isFunction.ts'

import { NN } from './NN.ts'
import { Falsy } from './types/index.ts'
/**
* Creates a function that will process either the `onTrue` or the `onFalse` function depending upon the result of the condition predicate.
* Return the `onTrue` or the `onFalse` value depending upon the result of the condition `val`.
*
* @param condition - A predicate function
* @param onTrue - Any value or A function to invoke when the `condition` evaluates to a truthy value
* @param onFalse - Any value or A function to invoke when the `condition` evaluates to a falsy value
* @returns A new function that will process either the `onTrue` or the `onFalse` function depending upon the result of the `condition` predicate
* @param val - A predicate value
* @param onTrue - The `val` evaluates to a truthy value
* @param onFalse - The `val` evaluates to a falsy value
* @returns The result of `!!val` ? `onTrue` : `onFalse`
*
* @example
* ```ts
* ifElse((x: number) => x > 10, 'big', 'small')(20) // 'big'
* const fn = ifElse((x: number) => x > 10, (x) => x + 1, (x) => x - 1)
* fn(11) // 12
* fn(9) // 8
* ifElse(true, 1, 0) // 1
* ifElse(false, 1, 0) // 0
* ifElse(undefined, 1, 0) // 0
* ```
*
* @category `Logic`
*
* @see Related to {@link ifElseFn}
*
* @beta
*/
const ifElse = <V, R extends boolean, T, F>(
condition: (val: V) => R,
onTrue: T | ((val: V) => T),
onFalse: F | ((val: V) => F)
) => (val: V): R extends true ? T : R extends false ? F : T | F => {
if (condition(val)) {
return isFunction(onTrue)
? (onTrue as (val: V) => T)(val)
: ((onTrue as T) as any)
} else {
return isFunction(onFalse)
? (onFalse as (val: V) => F)(val)
: ((onFalse as F) as any)
}
}
const ifElse = <V, T, F>(
val: V,
onTrue: T,
onFalse: F
): V extends Falsy ? F : V extends true ? T : T | F =>
(NN(val) ? onTrue : onFalse) as V extends Falsy
? F
: V extends true
? T
: T | F

export { ifElse }
42 changes: 42 additions & 0 deletions src/ifElseFn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2021-present the Fonction authors. All rights reserved. MIT license.
import { isFunction } from './isFunction.ts'
import { Falsy } from './types/index.ts'
/**
* Creates a function that will process either the `onTrue` or the `onFalse` function depending upon the result of the condition predicate.
*
* @param condition - A predicate function
* @param onTrue - Any value or A function to invoke when the `condition` evaluates to a truthy value
* @param onFalse - Any value or A function to invoke when the `condition` evaluates to a falsy value
* @returns A new function that will process either the `onTrue` or the `onFalse` function depending upon the result of the `condition` predicate
*
* @example
* ```ts
* ifElseFn((x: number) => x > 10, 'big', 'small')(20) // 'big'
* const fn = ifElseFn((x: number) => x > 10, (x) => x + 1, (x) => x - 1)
* fn(11) // 12
* fn(9) // 8
* ```
*
* @category `Logic`
*
* @see Related to {@link ifElse}
*
* @beta
*/
const ifElseFn = <V, R, T, F>(
condition: (val: V) => R,
onTrue: T | ((val: V) => T),
onFalse: F | ((val: V) => F)
) => (val: V): R extends true ? T : R extends Falsy ? F : T | F => {
if (condition(val)) {
return isFunction(onTrue)
? (onTrue as (val: V) => T)(val)
: ((onTrue as T) as any)
} else {
return isFunction(onFalse)
? (onFalse as (val: V) => F)(val)
: ((onFalse as F) as any)
}
}

export { ifElseFn }
57 changes: 20 additions & 37 deletions test/ifElse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,31 @@ import { ifElse } from '../src/ifElse.ts'
import { assertEqual } from './asserts.ts'

Deno.test('ifElse', () => {
const table: [
(val: any) => boolean,
((val: unknown) => boolean) | unknown,
((val: unknown) => boolean) | unknown,
unknown,
unknown
][] = [
[() => true, 1, 0, 1, 1],
[() => false, 1, 0, 1, 0],
[(x: unknown) => !!x, 1, 0, 1, 1],
[(x: unknown) => !!x, 1, 0, 0, 0],
[(x: unknown) => !!x, () => 2, 0, 1, 2],
[(x: unknown) => !!x, () => 2, () => 3, 0, 3],
[(x: unknown) => !!x, (x: number) => x + 1, () => 3, 1, 2],
[(x: unknown) => !!x, (x: number) => x + 1, (x: number) => x - 1, 0, -1]
const table: [unknown, unknown, unknown, unknown][] = [
[true, 1, 0, 1],
[{}, 1, 0, 1],
[[], 1, 0, 1],
['hello', 1, 0, 1],
[false, 1, 0, 0],
['', 1, 0, 0],
[NaN, 1, 0, 0],
[undefined, 1, 0, 0],
[null, 1, 0, 0],
[0, 1, 0, 0]
]

table.forEach(([condition, onTrue, onFalse, val, expected]) => {
table.forEach(([val, onTrue, onFalse, expected]) => {
assertEquals(
ifElse(condition, onTrue, onFalse)(val),
ifElse(val, onTrue, onFalse),
expected,
`ifElse(${condition}, ${onTrue}, ${onFalse})(${val}) -> ${expected}`
`ifElse(${val}, ${onTrue}, ${onFalse}) -> ${expected}`
)
})

assertEqual<number>(ifElse(() => true as const, 1, 0)(1))
assertEqual<1>(ifElse(() => true as const, 1 as const, 0 as const)(1))
assertEqual<0>(ifElse(() => false as const, 1 as const, 0 as const)(1))
assertEqual<1 | 0>(ifElse(() => true as boolean, 1 as const, 0 as const)(1))
assertEqual<1 | 0>(ifElse((x: string) => !!x, 1 as const, 0 as const)(''))
assertEqual<number>(
ifElse(
(x: number) => !!x,
(x: number) => x + 1,
0 as const
)(0)
)
assertEqual<number>(
ifElse(
(x: number) => !!x,
(x: number) => x + 1,
(x: number) => x - 1
)(0)
)
assertEqual<number>(ifElse(true, 1, 0))
assertEqual<number>(ifElse(true as const, 1, 0))
assertEqual<1>(ifElse(true as const, 1 as const, 0))
assertEqual<0>(ifElse(false as const, 1 as const, 0 as const))
assertEqual<1 | ''>(ifElse(false, 1 as const, '' as const))
assertEqual<1 | ''>(ifElse({}, 1 as const, '' as const))
})
55 changes: 55 additions & 0 deletions test/ifElseFn.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2021-present the Fonction authors. All rights reserved. MIT license.
import { assertEquals } from '../deps.ts'
import { ifElseFn } from '../src/ifElseFn.ts'
import { assertEqual } from './asserts.ts'

Deno.test('ifElseFn', () => {
const table: [
(val: any) => boolean,
((val: unknown) => boolean) | unknown,
((val: unknown) => boolean) | unknown,
unknown,
unknown
][] = [
[() => true, 1, 0, 1, 1],
[() => false, 1, 0, 1, 0],
[(x: unknown) => !!x, 1, 0, 1, 1],
[(x: unknown) => !!x, 1, 0, 0, 0],
[(x: unknown) => !!x, () => 2, 0, 1, 2],
[(x: unknown) => !!x, () => 2, () => 3, 0, 3],
[(x: unknown) => !!x, (x: number) => x + 1, () => 3, 1, 2],
[(x: unknown) => !!x, (x: number) => x + 1, (x: number) => x - 1, 0, -1]
]

table.forEach(([condition, onTrue, onFalse, val, expected]) => {
assertEquals(
ifElseFn(condition, onTrue, onFalse)(val),
expected,
`ifElseFn(${condition}, ${onTrue}, ${onFalse})(${val}) -> ${expected}`
)
})

assertEqual<number>(ifElseFn(() => true as const, 1, 0)(1))
assertEqual<1>(ifElseFn(() => true as const, 1 as const, 0 as const)(1))
assertEqual<0>(ifElseFn(() => false as const, 1 as const, 0 as const)(1))
assertEqual<0>(ifElseFn(() => '' as const, 1 as const, 0 as const)(1))
assertEqual<0>(ifElseFn(() => undefined, 1 as const, 0 as const)(1))
assertEqual<0>(ifElseFn(() => null, 1 as const, 0 as const)(1))
assertEqual<0>(ifElseFn(() => 0 as const, 1 as const, 0 as const)(1))
assertEqual<1 | 0>(ifElseFn(() => true as boolean, 1 as const, 0 as const)(1))
assertEqual<1 | 0>(ifElseFn((x: string) => !!x, 1 as const, 0 as const)(''))
assertEqual<number>(
ifElseFn(
(x: number) => !!x,
(x: number) => x + 1,
0 as const
)(0)
)
assertEqual<number>(
ifElseFn(
(x: number) => !!x,
(x: number) => x + 1,
(x: number) => x - 1
)(0)
)
})

0 comments on commit a13525b

Please sign in to comment.