@bemoje/fn
v2.0.0
Published
Higher-order function utilities for argument binding, context manipulation, spying, and method wrapping.
Maintainers
Readme
@bemoje/fn
Higher-order function utilities for argument binding, context manipulation, spying, and method wrapping.
Exports
- bindArg: Binds a specified argument to the provided function, returning a new function that requires only the remaining arguments at call time.
- bindArgs: Binds specified arguments to the provided function, returning a new function that requires only the remaining arguments at call time.
- dethisify: Converts a function from a class method by by making the first argument take the place of the 'this' context. The reverse of
- functionSpy: Wraps a function so that the given
- setLength: Set the length of a function.
- setName: Set the name of a function.
- setNameAndLength: Preserves the name and length of a function or class constructor
- thisProxy: Returns a function that redirects or 'proxies' the 'this' context of the input function to a property of a given key.
- thisify: Converts a function to a class method by making the 'this' context the first argument.
- transformReturnValue: Wraps a function to transform its return value using a transform function.
- wrapMethods: Wrap methods, getters and setters of an object with custom logic.
Installation
npm install @bemoje/fnUsage
Bind Arguments
Partially apply arguments at specific positions:
import { bindArg, bindArgs } from '@bemoje/fn'
function greet(greeting: string, name: string, punctuation: string) {
return `${greeting}, ${name}${punctuation}`
}
const greetHello = bindArg(greet, 0, 'Hello')
greetHello('World', '!') // 'Hello, World!'
const greetHelloWorld = bindArgs(greet, { 0: 'Hello', 1: 'World' })
greetHelloWorld('!') // 'Hello, World!'Convert Between this and First Argument
import { thisify, dethisify } from '@bemoje/fn'
// Convert a standalone function into a method
function getFullName(target: { first: string; last: string }) {
return `${target.first} ${target.last}`
}
const method = thisify(getFullName)
// Now usable as: obj.getFullName = method
// Convert a method into a standalone function
const standalone = dethisify(method)
standalone({ first: 'John', last: 'Doe' }) // 'John Doe'Redirect this Context
import { thisProxy } from '@bemoje/fn'
function getName(this: { name: string }) {
return this.name
}
// Redirect `this` to a property key
const proxied = thisProxy(getName, 'inner')
// When called on { inner: { name: 'test' } }, returns 'test'Function Spy
Wrap functions with before/after hooks:
import { functionSpy, type IFunctionSpyStrategy } from '@bemoje/fn'
const timingStrategy: IFunctionSpyStrategy<unknown, number> = {
onInvoke(_ctx, _args) {
return performance.now()
},
onReturn(startTime, retval) {
console.log(`Took ${performance.now() - startTime}ms`)
return retval
},
}
const timed = functionSpy(myFunction, timingStrategy)Transform Return Values
import { transformReturnValue } from '@bemoje/fn'
function getItems() {
return [3, 1, 2]
}
const getSorted = transformReturnValue(getItems, (arr) => arr.sort())
getSorted() // [1, 2, 3]Wrap Object Methods
import { wrapMethods } from '@bemoje/fn'
wrapMethods(myObject, {
filter: (_target, key, _type, _des) => key !== 'skip',
onMethod: (_target, key, original) => {
return function (...args) {
console.log(`Calling ${String(key)}`)
return original.apply(this, args)
}
},
})Function Metadata
import { setName, setLength, setNameAndLength } from '@bemoje/fn'
const fn = () => {}
setName('myFn', fn) // fn.name === 'myFn'
setLength(3, fn) // fn.length === 3