Last active
October 11, 2024 15:04
-
-
Save webbower/ceb11396b28f9906d01a4d88c4f7e466 to your computer and use it in GitHub Desktop.
Native JS extensions π±
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function before<A, B, C>(this: (a: A) => B, g: (b: B) => C): (a: A) => C { | |
const f = this; | |
return function (x) { | |
return g(f(x)); | |
// return g.call(this, f.call(this, x)); | |
}; | |
}; | |
function after<A, B, C>(this: (b: B) => C, g: (a: A) => B): (a: A) => C { | |
const f = this; | |
return function (x) { | |
return f(g(x)); | |
// return f.call(this, g.call(this, x)); | |
}; | |
}; | |
interface Function { | |
before: typeof before; | |
bfr: typeof before; | |
after: typeof after; | |
ftr: typeof after; | |
} | |
Function.prototype.before = Function.prototype.bfr = before; | |
Function.prototype.after = Function.prototype.ftr = after; | |
const toUpper = (str: string): string => str.toUpperCase(); | |
const len = (x: string): number => x.length; | |
const double = (x: number): number => x * 2 | |
const isEven = (x: number): boolean => x % 2 === 0; | |
const myFn = toUpper.bfr(len).before(double).before(isEven); | |
const myFn2 = isEven.ftr(double).after(len).ftr(toUpper); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @see https://stackoverflow.com/a/3561711 | |
*/ | |
RegExp.xEscape = function escape(string) { | |
return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&'); | |
}; | |
Function.prototype.xPartial = function partial(...args) { | |
return this.bind(null, ...args); | |
}; | |
Object.defineProperties(Number.prototype, { | |
xDecimal: { | |
value: function decimal() { | |
// TODO fix precision @see https://stackoverflow.com/questions/4512306/get-decimal-portion-of-a-number-with-javascript | |
return Number(this) % 1; | |
}, | |
configurable: true, | |
}, | |
}); | |
// isEmpty() | |
const hasOwnProperty = Object.prototype.hasOwnProperty; | |
Object.prototype.xIsEmpty = function isEmpty() { | |
for (let p in this) { | |
if (hasOwnProperty.call(this, p)) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
Boolean.prototype.xIsEmpty = function isEmpty() { | |
return Boolean(this) === false; | |
}; | |
Number.prototype.xIsEmpty = function isEmpty() { | |
return Number.isNaN(this); | |
}; | |
BigInt.prototype.xIsEmpty = function isEmpty() { | |
return false; | |
}; | |
String.prototype.xIsEmpty = function isEmpty() { | |
return String(this) === ''; | |
}; | |
Array.prototype.xIsEmpty = function isEmpty() { | |
return this.length === 0; | |
}; | |
Symbol.prototype.xIsEmpty = function isEmpty() { | |
return false; | |
}; | |
RegExp.prototype.xIsEmpty = function isEmpty() { | |
return false; | |
}; | |
Promise.prototype.xIsEmpty = function isEmpty() { | |
return false; | |
}; | |
Function.prototype.xIsEmpty = function isEmpty() { | |
return false; | |
}; | |
Map.prototype.xIsEmpty = function isEmpty() { | |
return this.size === 0; | |
}; | |
Set.prototype.xIsEmpty = function isEmpty() { | |
return this.size === 0; | |
}; | |
// Map over own props for an object | |
Object.prototype.xMap = function map(mapFn, thisArg) { | |
const result = {}; | |
for (const key in this) { | |
if (Object.hasOwn(this, key)) { | |
result[key] = mapFn.call(thisArg, this[key], key, this); | |
} | |
} | |
return result; | |
} | |
// Time extensions for Number | |
Object.defineProperties(Number.prototype, { | |
xSeconds: { | |
value: function seconds() { | |
return Number(this) * 1000; | |
}, | |
configurable: true, | |
}, | |
xMinutes: { | |
value: function minutes() { | |
return this.xSeconds() * 60; | |
}, | |
configurable: true, | |
}, | |
xHours: { | |
value: function hours() { | |
return this.xMinutes() * 60; | |
}, | |
configurable: true, | |
}, | |
xDays: { | |
value: function days() { | |
return this.xHours() * 24; | |
}, | |
configurable: true, | |
}, | |
xWeeks: { | |
value: function weeks() { | |
return this.xDays() * 7; | |
}, | |
configurable: true, | |
}, | |
// xMonths: { | |
// value: function months(monthIndex, isLeapYear = false) { | |
// if (typeof monthIndex !== 'number' || monthIndex < 0 || monthIndex > 11) { | |
// throw new TypeError(`Number.xMonths() expects monthIndex to be a number between 0 and 11 inclusive. ${monthIndex} given.`); | |
// } | |
// // TODO Add checking for isLeapYear | |
// const daysInMonth = ( | |
// monthIndex === 1 ? (isLeapYear ? 29 : 28) // February and Leap Year check | |
// : [3, 5, 8, 10].indcludes(monthIndex) ? 30 // April, June, Sept, Nov are 30-day months | |
// : 31 // The rest are 31-day months | |
// ); | |
// return this.days() * daysInMonth; | |
// }, | |
// configurable: true, | |
// }, | |
// xYears: { | |
// value: function years(isLeapYear = false) { | |
// // TODO Figure out how to account for leap years for more than 1 year | |
// return this.days() * (isLeapYear ? 366 : 365); | |
// }, | |
// configurable: true, | |
// }, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment