Skip to content

Commit

Permalink
fix: Improve type inference for chain function
Browse files Browse the repository at this point in the history
  • Loading branch information
fResult committed Dec 4, 2023
1 parent 03dd315 commit 4c2ede2
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 5 deletions.
51 changes: 47 additions & 4 deletions src/curry.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,55 @@
export type UnaryFunc<T, R> = (arg: T) => R
export type Func<TArgs = any, KReturn = any | void> = (
...args: TArgs[]
) => KReturn

export const chain =
(...funcs: Func[]) =>
(...args: any[]) => {
return funcs.slice(1).reduce((acc, fn) => fn(acc), funcs[0](...args))
export function chain<T1, T2, R>(
fn1: UnaryFunc<T1, T2>,
fn2: UnaryFunc<T2, R>
): UnaryFunc<T1, R>
export function chain<T1, T2, T3, R>(
fn1: UnaryFunc<T1, T2>,
fn2: UnaryFunc<T2, T3>,
fn3: UnaryFunc<T3, R>
): UnaryFunc<T1, R>
export function chain<T1, T2, T3, T4, R>(
fn1: UnaryFunc<T1, T2>,
fn2: UnaryFunc<T2, T3>,
fn3: UnaryFunc<T3, T4>,
fn4: UnaryFunc<T4, R>
): UnaryFunc<T1, R>
export function chain<T1, T2, T3, T4, T5, R>(
fn1: UnaryFunc<T1, T2>,
fn2: UnaryFunc<T2, T3>,
fn3: UnaryFunc<T3, T4>,
fn4: UnaryFunc<T4, T5>,
fn5: UnaryFunc<T5, R>
): UnaryFunc<T1, R>
export function chain<T1, T2, T3, T4, T5, T6, R>(
fn1: UnaryFunc<T1, T2>,
fn2: UnaryFunc<T2, T3>,
fn3: UnaryFunc<T3, T4>,
fn4: UnaryFunc<T4, T5>,
fn5: UnaryFunc<T5, T6>,
fn6: UnaryFunc<T6, R>
): UnaryFunc<T1, R>
export function chain<T1, T2, T3, T4, T5, T6, T7, R>(
fn1: UnaryFunc<T1, T2>,
fn2: UnaryFunc<T2, T3>,
fn3: UnaryFunc<T3, T4>,
fn4: UnaryFunc<T4, T5>,
fn5: UnaryFunc<T5, T6>,
fn6: UnaryFunc<T6, T7>,
fn7: UnaryFunc<T7, R>
): UnaryFunc<T1, R>
export function chain<T = any, R = any>(
...fns: ((arg: any) => any)[]
): UnaryFunc<T, R>
export function chain(...funcs: Func[]): Func {
return function forX(initialParam: Parameters<Func>[0]) {
return funcs.reduce((acc, fn) => fn(acc), initialParam)
}
}

export const compose = (...funcs: Func[]) => {
return funcs.reverse().reduce((acc, fn) => fn(acc))
Expand Down
47 changes: 46 additions & 1 deletion src/tests/curry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,54 @@ describe('curry module', () => {
const addFive = (num: number) => num + 5
const twoX = (num: number) => num * 2
const func = _.chain(genesis, addFive, twoX)
const result = func()
const result = func(0)
assert.equal(result, 10)
})

test('calls add(1), then addFive, then twoX functions by 1', () => {
const add = (y: number) => (x: number) => x + y
const addFive = (num: number) => num + 5
const twoX = (num: number) => num * 2
const func = _.chain(add(1), addFive, twoX)
const result = func(1)
assert.equal(result, 14)
})

test('calls add(2), then addFive, then twoX, then repeatX functions by 1', () => {
const add = (y: number) => (x: number) => x + y
const addFive = (num: number) => num + 5
const twoX = (num: number) => num * 2
const repeatX = (num: number) => 'X'.repeat(num)
const func = _.chain(add(2), addFive, twoX, repeatX)
const result = func(1)
assert.equal(result, 'XXXXXXXXXXXXXXXX')
})

test('calls addFive, then add(2), then twoX, then repeatX functions by 1', () => {
const add = (y: number) => (x: number) => x + y
const addFive = (num: number) => num + 5
const twoX = (num: number) => num * 2
const repeatX = (num: number) => 'X'.repeat(num)
const func = _.chain(addFive, add(2), twoX, repeatX)
const result = func(1)
assert.equal(result, 'XXXXXXXXXXXXXXXX')
})

test('calls getName, then upperCase functions as a mapper for User[]', () => {
type User = { id: number; name: string }
const users: User[] = [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'John Smith' },
{ id: 3, name: 'John Wick' }
]
const getName = <T extends { name: string }>(item: T) => item.name
const upperCase: (x: string) => Uppercase<string> = (text: string) =>
text.toUpperCase() as Uppercase<string>

const getUpperName = _.chain<User, Uppercase<string>>(getName, upperCase)
const result = users.map(getUpperName)
assert.deepEqual(result, ['JOHN DOE', 'JOHN SMITH', 'JOHN WICK'])
})
})

describe('proxied function', () => {
Expand Down

0 comments on commit 4c2ede2

Please sign in to comment.