Well-typed functions for objects
yarn add @typed/objects
# or
npm install --save @typed/objectsAll functions are curried!
A StrMap type. Works as a readonly object.
export type StrMap<K extends string, V> = Readonly<Record<K, V>>
Returns a deep clone of a value.
See the code
export function clone<A>(obj: A): A {
return _clone(obj, [], [], true)
}
function _clone(value: any, refFrom: Array<any>, refTo: Array<any>, deep: boolean): any {
function copy(copiedValue: any) {
const length = refFrom.length
let i = 0
for (; i < length; ++i) if (value === refFrom[i]) return refTo[i]
refFrom[i + 1] = value
refTo[i + 1] = copiedValue
for (const key in value) {
if (!value.hasOwnProperty(key)) continue
copiedValue[key] = deep ? _clone(value[key] as any, refFrom, refTo, true) : value[key]
}
return copiedValue
}
switch (typeOf(value)) {
case 'Object':
return copy({})
case 'Array':
return copy([])
case 'Date':
return new Date(value.valueOf())
case 'RegExp':
return cloneRegexp(value)
default:
return value
}
}
function cloneRegexp(pattern: RegExp): RegExp {
return new RegExp(
pattern.source,
(pattern.global ? 'g' : '') +
(pattern.ignoreCase ? 'i' : '') +
(pattern.multiline ? 'm' : '') +
(pattern.sticky ? 'y' : '') +
(pattern.unicode ? 'u' : '')
)
}
Given a property key and an object returns true if that object has a property at the given property key.
See the code
export const hasOwnProperty: HasOwnProperty = invoker<Object, PropertyKey, boolean>(
1,
'hasOwnProperty'
)
export type HasOwnProperty = {
<O extends object>(key: PropertyKey, object: O): boolean
<O extends object>(key: PropertyKey): (object: O) => boolean
(key: PropertyKey): <O>(object: O) => boolean
}
Turns a named method with a specified arity into a function that can be called directly supplied with arguments and a target object. The returned function is curried and accepts arity + 1 parameters where the final parameter is the target object.
See the code
export const invoker: InvokerFn = (curry2(<O, R>(arity: number, method: keyof O) =>
curryN((arity + 1) as any, function(): R {
const target = arguments[arity]
return target[method].apply(target, Array.prototype.slice.call(arguments, 0, arity))
})
) as any) as InvokerFn
Returns true if an object or array is empty.
See an example
import { isEmpty } from '167'
isEmpty({}) // true
isEmpty({ a: 1, b: 2 }) // false
isEmpty([]) // true
isEmpty([ 1, 2, 3 ]) // false
isEmpty(void 0) // false
isEmpty(null) // falseSee the code
export const isEmpty: <A>(object: A) => boolean = ifElse(
x => x === null || x === void 0,
always(false),
pipe(
keys,
length,
equals(0)
)
)
Returns the keys of an object.
See the code
export const keys = <A>(obj: A): Array<keyof A> => (Object.keys(obj) as any) as Array<keyof A>
Returns the value of the property length
See the code
export const length = prop('length')
Given a path to a value it returns a Lens that operates on that value.
See the code
export const lensPath: LensPath = function(path: ArrayLike<string>): Lens<any, any> {
return apply(Array.from(path).map(lensProp), pipeLenses)
}
Creates a lens that operates on an object's property.
See the code
export const lensProp = <A, K extends keyof A = keyof A>(key: K): Lens<A, A[K]> =>
lens(prop(key), (x, o) => set(key, x, o))
Given a path to a value and an object it returns the values contained at that path.
See the code
export const path: Path = curry2(function(path: ArrayLike<string>, obj: any): any {
return lensPath<any, any>(path).view(obj)
})
Returns the value of a property from an object.
See the code
export const prop: Prop = curry2(<A, K extends keyof A>(key: K, obj: A): A[K] => obj[key])
Sets the property on an object.
See the code
export const set = curry3(function __set<
Key extends PropertyKey,
A,
O extends { readonly: { [K in Key]: A } }
>(key: Key, value: A, obj: O): O {
const clonedObj = clone(obj)
;(clonedObj as any)[key] = value
return clonedObj
}) as SetArity3
export type SetArity3 = {
<A, O extends { readonly [key: number]: A }>(key: number, value: A, obj: O): O
<Key extends PropertyKey, A, O extends Readonly<Record<Key, A>>>(key: Key, value: A, obj: O): O
<A>(key: number, value: A): <O extends { readonly [key: number]: A }>(obj: O) => O
<Key extends PropertyKey, A>(key: Key, value: A): SetArity1<Key, A>
(key: number): SetArity2Number
<Key extends PropertyKey>(key: Key): SetArity2<Key>
}
export type SetArity2Number = {
<A, O extends { readonly [key: number]: A }>(value: A, obj: O): O
<A>(value: A): <O extends { readonly [key: number]: A }>(obj: O) => O
<A, O extends { readonly [key: number]: A }>(value: A): (obj: O) => O
}
export type SetArity2<Key extends PropertyKey> = {
<A, O extends Readonly<Record<Key, A>>>(value: A, obj: O): O
<A>(value: A): SetArity1<Key, A>
}
export type SetArity1<Key extends PropertyKey, A> = {
<O extends Readonly<Record<Key, A>>>(obj: O): O
}
Returns the type of a value.
See the code
export function typeOf(value: string): 'String'
export function typeOf(value: number): 'Number'
export function typeOf(value: null): 'Null'
export function typeOf(value: undefined): 'Undefined'
export function typeOf(value: undefined): 'Undefined'
export function typeOf(value: any): string
export function typeOf(value: any): string {
if (value === null) return 'Null'
if (value === void 0) return `Undefined`
return Object.prototype.toString.call(value).slice(8, -1)
}
Returns the values of an object.
See the code
export const values = <A>(obj: A): Array<A[keyof A]> =>
Object.keys(obj).map(key => obj[key as keyof A])