Added and, or, pipe, attr, nn, nu, nnu, bool and fmap

This commit is contained in:
Michaël Lemaire 2019-09-30 00:13:03 +02:00
parent 280ec25df9
commit 515612f089
5 changed files with 407 additions and 60 deletions

View file

@ -18,10 +18,62 @@ Issues can be reported on [GitLab](https://gitlab.com/thunderk/tk-functional/iss
Functions
---------
**nop** does nothing (useful for some callbacks):
**always** and **never** return true and false respectively
```typescript
new ConstructorWithMandatoryCallback(nop)
always() // => true
never() // => false
```
**and** and **or** combines predicates
```typescript
const a = and((x: number) => x > 2, (x: number) => x < 5);
a(2) // => false
a(3) // => true
a(4) // => true
a(5) // => false
const o = or((x: number) => x < 2, (x: number) => x > 3);
o(1) // => true
o(2) // => false
o(3) // => false
o(4) // => true
```
**attr** gets an object's attribute:
```typescript
const getx = attr("x");
getx({x: 3}); // => 3
```
**bool** checks for boolean equivalence (in a broader sense than !(!(val))):
```typescript
bool(undefined); // => false
bool(null); // => false
bool(-1); // => true
bool(0); // => false
bool(1); // => true
bool(""); // => false
bool(" "); // => true
bool("abc"); // => true
bool([]); // => false
bool([1, 2, 3]); // => true
bool({}); // => false
bool({x: 1}); // => true
```
**cmp** simplifies the use of array sorting:
```typescript
[8, 3, 5].sort(cmp()) // => [3, 5, 8]
[8, 3, 5].sort(cmp({ reverse: true })) // => [8, 5, 3]
[-2, 8, -7].sort(cmp({ key: Math.abs })) // => [-2, -7, 8]
```
**identity** returns its argument untouched:
@ -30,11 +82,26 @@ new ConstructorWithMandatoryCallback(nop)
a === identity(a) // => true
```
**always** and **never** return true and false respectively
**nn**, **nu** and **nnu** checks at run-time for null or undefined:
```typescript
always() // => true
never() // => false
nn(undefined) // => undefined
nn(null) // => Error
nn(1) // => 1
nu(undefined) // => Error
nu(null) // => null
nu(1) // => 1
nnu(undefined) // => Error
nnu(null) // => Error
nnu(1) // => 1
```
**nop** does nothing (useful for some callbacks):
```typescript
new ConstructorWithMandatoryCallback(nop)
```
**partial** applies a partial configuration object as first argument of compatible functions:
@ -45,10 +112,9 @@ const plus1 = partial({a: 1}, sum);
plus1({b: 8}) // => 9
```
**cmp** simplifies the use of array sorting:
**pipe** chains two functions as one:
```typescript
[8, 3, 5].sort(cmp()) // => [3, 5, 8]
[8, 3, 5].sort(cmp({ reverse: true })) // => [8, 5, 3]
[-2, 8, -7].sort(cmp({ key: Math.abs })) // => [-2, -7, 8]
const f = pipe((x: number) => x * 2, (x: number) => x + 1);
f(3) // => 7 ((3 * 2) + 1)
```

123
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "tk-functional",
"version": "0.1.4",
"version": "0.1.5",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -1185,9 +1185,9 @@
"dev": true
},
"@types/node": {
"version": "12.7.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.7.tgz",
"integrity": "sha512-4jUncNe2tj1nmrO/34PsRpZqYVnRV1svbU78cKhuQKkMntKB/AmdLyGgswcZKjFHEHGpiY8pVD8CuVI55nP54w==",
"version": "12.7.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz",
"integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==",
"dev": true
},
"@types/q": {
@ -1920,9 +1920,9 @@
}
},
"commander": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
"version": "2.20.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.1.tgz",
"integrity": "sha512-cCuLsMhJeWQ/ZpsFTbE765kvVfoeSddc4nU3up4fV+fDBcfUXnbITJ+JzhkdjzOqhURjZgujxaioam4RM9yGUg==",
"dev": true
},
"component-emitter": {
@ -2549,9 +2549,9 @@
}
},
"electron-to-chromium": {
"version": "1.3.266",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.266.tgz",
"integrity": "sha512-UTuTZ4v8T0gLPHI7U75PXLQePWI65MTS3mckRrnLCkNljHvsutbYs+hn2Ua/RFul3Jt/L3Ht2rLP+dU/AlBfrQ==",
"version": "1.3.269",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.269.tgz",
"integrity": "sha512-t2ZTfo07HxkxTOUbIwMmqHBSnJsC9heqJUm7LwQu2iSk0wNhG4H5cMREtb8XxeCrQABDZ6IqQKY3yZq+NfAqwg==",
"dev": true
},
"emoji-regex": {
@ -2886,9 +2886,9 @@
}
},
"filesize": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-4.2.0.tgz",
"integrity": "sha512-bdS2UP98MZzLyTZzhuSH5ctAWyDt81n5xMti9BSdmgPXjjENLDz5Bmbk2R7ATVw/HRysZzWA2JIPgcSAOimWpw==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-4.2.1.tgz",
"integrity": "sha512-bP82Hi8VRZX/TUBKfE24iiUGsB/sfm2WUrwTQyAzQrhO3V9IhcBBNBXMyzLY5orACxRyYJ3d2HeRVX+eFv4lmA==",
"dev": true
},
"fill-range": {
@ -3628,9 +3628,9 @@
}
},
"handlebars": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.1.tgz",
"integrity": "sha512-c0HoNHzDiHpBt4Kqe99N8tdLPKAnGCQ73gYMPWtAYM4PwGnf7xl8PBUHJqh9ijlzt2uQKaSRxbXRt+rZ7M2/kA==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.4.0.tgz",
"integrity": "sha512-xkRtOt3/3DzTKMOt3xahj2M/EqNhY988T+imYSlMgs5fVhLN2fmKVVj0LtEGmb+3UUYV5Qmm1052Mm3dIQxOvw==",
"dev": true,
"requires": {
"neo-async": "^2.6.0",
@ -5034,6 +5034,12 @@
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
"dev": true
},
"memorystream": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
"integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=",
"dev": true
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@ -5262,9 +5268,9 @@
}
},
"node-releases": {
"version": "1.1.32",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.32.tgz",
"integrity": "sha512-VhVknkitq8dqtWoluagsGPn3dxTvN9fwgR59fV3D7sLBHe0JfDramsMI8n8mY//ccq/Kkrf8ZRHRpsyVZ3qw1A==",
"version": "1.1.33",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.33.tgz",
"integrity": "sha512-I0V30bWQEoHb+10W8oedVoUrdjW5wIkYm0w7vvcrPO95pZY738m1k77GF5sO0vKg5eXYg9oGtrMAETbgZGm11A==",
"dev": true,
"requires": {
"semver": "^5.3.0"
@ -5303,6 +5309,23 @@
"integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==",
"dev": true
},
"npm-run-all": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"memorystream": "^0.3.1",
"minimatch": "^3.0.4",
"pidtree": "^0.3.0",
"read-pkg": "^3.0.0",
"shell-quote": "^1.6.1",
"string.prototype.padend": "^3.0.0"
}
},
"npm-run-path": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@ -5607,6 +5630,12 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
},
"pidtree": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz",
"integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==",
"dev": true
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
@ -6349,9 +6378,9 @@
"dev": true
},
"react-is": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz",
"integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==",
"version": "16.10.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.1.tgz",
"integrity": "sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw==",
"dev": true
},
"read-pkg": {
@ -6621,14 +6650,14 @@
}
},
"rollup": {
"version": "1.21.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-1.21.4.tgz",
"integrity": "sha512-Pl512XVCmVzgcBz5h/3Li4oTaoDcmpuFZ+kdhS/wLreALz//WuDAMfomD3QEYl84NkDu6Z6wV9twlcREb4qQsw==",
"version": "1.22.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-1.22.0.tgz",
"integrity": "sha512-x4l4ZrV/Mr/x/jvFTmwROdEAhbZjx16yDRTVSKWh/i4oJDuW2dVEbECT853mybYCz7BAitU8ElGlhx7dNjw3qQ==",
"dev": true,
"requires": {
"@types/estree": "0.0.39",
"@types/node": "^12.7.5",
"acorn": "^7.0.0"
"@types/estree": "*",
"@types/node": "*",
"acorn": "^7.1.0"
},
"dependencies": {
"acorn": {
@ -6640,9 +6669,9 @@
}
},
"rollup-plugin-alias": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-alias/-/rollup-plugin-alias-2.0.0.tgz",
"integrity": "sha512-JVwxV9nwzjc0q7JmrV9jvZlJ8FykNd5r7RmYps8i/7v+vcmmVpeMvXrljhCboYErf4VZ2z9FEj+fP7eJlEGfug==",
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-alias/-/rollup-plugin-alias-2.0.1.tgz",
"integrity": "sha512-/wOySYmFzR1TPijsiNBOAV12HYPs7GZtAuim2LKdk5V6RnQSZ34ueVgkFfjJffe/HIFR6Jdwc4+7YOlY5uty4w==",
"dev": true,
"requires": {
"slash": "^3.0.0"
@ -6964,6 +6993,12 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"shell-quote": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
"integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==",
"dev": true
},
"shellwords": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
@ -7306,6 +7341,17 @@
"strip-ansi": "^5.1.0"
}
},
"string.prototype.padend": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz",
"integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.4.3",
"function-bind": "^1.0.2"
}
},
"string.prototype.trimleft": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
@ -7414,9 +7460,9 @@
"dev": true
},
"terser": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.3.2.tgz",
"integrity": "sha512-obxk4x19Zlzj9zY4QeXj9iPCb5W8YGn4v3pn4/fHj0Nw8+R7N02Kvwvz9VpOItCZZD8RC+vnYCDL0gP6FAJ7Xg==",
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.3.4.tgz",
"integrity": "sha512-Kcrn3RiW8NtHBP0ssOAzwa2MsIRQ8lJWiBG/K7JgqPlomA3mtb2DEmp4/hrUA+Jujx+WZ02zqd7GYD+QRBB/2Q==",
"dev": true,
"requires": {
"commander": "^2.20.0",
@ -7459,15 +7505,16 @@
}
},
"tk-base": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/tk-base/-/tk-base-0.2.0.tgz",
"integrity": "sha512-ZdXXxHxjByinZy1ZOo26WOjqwkDkQBAFr0U0pKHMtw7tyJyTvMrxxaf/gm6IoaJLcMQ+vdwqFP5t0nmVyhTrog==",
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/tk-base/-/tk-base-0.2.1.tgz",
"integrity": "sha512-oVFVHXYoknqLBSZRqJSg/+BrKAh24cMpXQyU/q0hH+dVPnd+uHQ1nsjE8U69phrYOSCWicVXH1CKfuaGtV0vWg==",
"dev": true,
"requires": {
"@types/jest": "^24.0.18",
"@types/node": "^12.7.7",
"@types/node": "^12.7.8",
"jest": "^24.9.0",
"microbundle": "^0.12.0-next.6",
"npm-run-all": "^4.1.5",
"ts-jest": "^24.1.0",
"ts-node": "^8.4.1",
"typescript": "^3.6.3"

View file

@ -1,6 +1,6 @@
{
"name": "tk-functional",
"version": "0.1.4",
"version": "0.1.5",
"description": "Typescript/Javascript helpers for functional-style programming",
"source": "src/index.ts",
"main": "dist/tk-functional.umd.js",
@ -11,19 +11,33 @@
"/dist"
],
"scripts": {
"test": "npx --no-install tk-base test",
"normalize": "npx --no-install tk-base normalize",
"build": "npx --no-install tk-base build",
"test": "jest",
"normalize": "tk-base",
"build": "microbundle build -f modern,umd",
"prepare": "npm run build",
"prepublishOnly": "npm test"
"prepublishOnly": "npm test",
"dev": "run-p dev:*",
"dev:test": "jest --watchAll",
"dev:build": "microbundle watch -f modern,umd"
},
"author": {
"name": "Michaël Lemaire",
"url": "https://thunderk.net"
},
"license": "ISC",
"repository": {
"type": "git",
"url": "https://code.thunderk.net/tslib/tk-functional.git"
},
"bugs": {
"url": "https://gitlab.com/thunderk/tk-functional/issues"
},
"homepage": "https://code.thunderk.net/tslib/tk-functional",
"keywords": [
"typescript"
],
"devDependencies": {
"tk-base": "^0.2.0"
"tk-base": "^0.2.1"
},
"dependencies": {}
}

View file

@ -1,19 +1,19 @@
import { always, cmp, identity, never, nop, partial } from "./index";
import { always, and, attr, bool, cmp, fmap, identity, never, nn, nnu, nop, nu, or, partial, pipe } from "./index";
describe("nop", () => {
describe(nop, () => {
it("does nothing", () => {
expect(nop()).toBeUndefined();
});
});
describe("identity", () => {
describe(identity, () => {
it("returns the argument untouched", () => {
expect(identity(5)).toBe(5);
expect(identity(null)).toBe(null);
});
});
describe("partial", () => {
describe(partial, () => {
it("applies systematically fixed configuration", () => {
const func = (conf: { a: number, b: string, c: number }) => `${conf.a}${conf.b}${conf.c}`;
const pfunc = partial({ b: "test" }, func);
@ -27,7 +27,7 @@ describe("partial", () => {
});
});
describe("cmp", () => {
describe(cmp, () => {
it("simplifies array sorting", () => {
expect([8, 3, 5].sort(cmp())).toEqual([3, 5, 8]);
expect([8, 3, 5, 8].sort(cmp({ reverse: true }))).toEqual([8, 8, 5, 3]);
@ -36,7 +36,7 @@ describe("cmp", () => {
});
});
describe("always", () => {
describe(always, () => {
it("returns true", () => {
expect(always()).toBe(true);
expect(always(true)).toBe(true);
@ -44,10 +44,123 @@ describe("always", () => {
});
});
describe("never", () => {
describe(never, () => {
it("returns false", () => {
expect(never()).toBe(false);
expect(never(true)).toBe(false);
expect(never(false)).toBe(false);
});
});
describe(and, () => {
it("combines predicates", () => {
const f = and((x: number) => x % 2 == 0, (x: number) => x > 5);
expect(f(0)).toBe(false);
expect(f(2)).toBe(false);
expect(f(8)).toBe(true);
expect(f(9)).toBe(false);
expect(f(10)).toBe(true);
});
});
describe(or, () => {
it("combines predicates", () => {
const f = or((x: number) => x % 2 == 0, (x: number) => x > 5);
expect(f(0)).toBe(true);
expect(f(1)).toBe(false);
expect(f(2)).toBe(true);
expect(f(8)).toBe(true);
expect(f(9)).toBe(true);
});
});
describe(pipe, () => {
it("pipes two functions", () => {
const f = pipe((x: number) => x * 2, (x: number) => x + 1);
expect(f(1)).toBe(3);
expect(f(2)).toBe(5);
expect(f(3)).toBe(7);
});
});
describe(attr, () => {
it("gets an attribute from an object", () => {
const getx = attr("x");
expect(getx({ x: 4, y: 5 })).toBe(4);
expect(getx({ x: undefined, y: 5 })).toBeUndefined();
});
});
describe(nn, () => {
it("checks for null", () => {
expect(nn(undefined)).toBeUndefined();
expect(nn(0)).toBe(0);
expect(nn("")).toBe("");
expect(nn([])).toEqual([]);
expect(() => nn(null)).toThrowError("null value");
});
});
describe(nu, () => {
it("checks for undefined", () => {
expect(nu(null)).toBe(null);
expect(nu(0)).toBe(0);
expect(nu("")).toBe("");
expect(nu([])).toEqual([]);
expect(() => nu(undefined)).toThrowError("undefined value");
});
});
describe(nnu, () => {
it("checks for null or undefined", () => {
expect(nnu(0)).toBe(0);
expect(nnu("")).toBe("");
expect(nnu([])).toEqual([]);
expect(() => nnu(undefined)).toThrowError("undefined value");
expect(() => nnu(null)).toThrowError("null value");
});
});
describe(bool, () => {
it("checks for boolean equivalent", () => {
expect(bool(null)).toBe(false);
expect(bool(undefined)).toBe(false);
expect(bool(false)).toBe(false);
expect(bool(true)).toBe(true);
expect(bool(-1)).toBe(true);
expect(bool(0)).toBe(false);
expect(bool(1)).toBe(true);
expect(bool("")).toBe(false);
expect(bool(" ")).toBe(true);
expect(bool("abc")).toBe(true);
expect(bool([])).toBe(false);
expect(bool([0])).toBe(true);
expect(bool([1, 2, 3])).toBe(true);
expect(bool(new Set())).toBe(false);
expect(bool(new Set([0]))).toBe(true);
expect(bool(new Set([1, 2, 3]))).toBe(true);
expect(bool({})).toBe(false);
expect(bool({ a: 5 })).toBe(true);
class Obj1 { };
class Obj2 { private x = 0 };
expect(bool(new Obj1())).toBe(false);
expect(bool(new Obj2())).toBe(true);
});
});
describe(fmap, () => {
it("applies map and filter on an array", () => {
expect(fmap()([1, 2, 3])).toEqual([1, 2, 3]);
expect(fmap((x: number) => x * 2)([1, 2, 3])).toEqual([2, 4, 6]);
expect(fmap(undefined, (x: number) => x % 2 == 0)([1, 2, 3])).toEqual([2]);
expect(fmap((x: number) => x * 2)([1, 2, 3])).toEqual([2, 4, 6]);
expect(fmap((x: number) => x * 2, (x: number) => x < 5)([1, 2, 3])).toEqual([2, 4]);
});
});

View file

@ -47,3 +47,110 @@ export const always = (...args: any[]) => true
* Predicate that always returns false
*/
export const never = (...args: any[]) => false
/**
* Apply a boolean "and" to merge predicates
*/
export function and<A extends any[]>(...predicates: ((...args: A) => boolean)[]): (...args: A) => boolean {
return (...args) => {
for (let p of predicates) {
if (!p(...args)) {
return false;
}
}
return true;
}
}
/**
* Apply a boolean "or" to merge predicates
*/
export function or<A extends any[]>(...predicates: ((...args: A) => boolean)[]): (...args: A) => boolean {
return (...args) => {
for (let p of predicates) {
if (p(...args)) {
return true;
}
}
return false;
}
}
/**
* Pipe the result of a function as first parameter of another, to create a new function
*/
export function pipe<IN extends any[], INT, R>(f1: (...args: IN) => INT, f2: (value: INT) => R): (...args: IN) => R {
return (...args: IN) => f2(f1(...args));
}
/**
* Attribute getter
*/
export function attr<K extends string>(name: K): <V, O extends Record<K, V>>(obj: O) => V {
return obj => obj[name];
}
/**
* Check that a value is not null, throwing an error if it is
*/
export function nn<T>(value: T | null): T {
if (value === null) {
throw new Error("null value");
} else {
return value;
}
}
/**
* Check that a value is not undefined, throwing an error if it is
*/
export function nu<T>(value: T | undefined): T {
if (typeof value === "undefined") {
throw new Error("undefined value");
} else {
return value;
}
}
/**
* Check that a value is not null nor undefined, throwing an error if it is
*/
export const nnu: <T>(value: T | null | undefined) => T = pipe(nn, nu);
/**
* Convert a value to a boolean (are considered falsy: 0, false, "", {}, [], null, undefined)
*/
export function bool<T>(value: T | null | undefined): value is T;
export function bool(value: any): boolean {
if (!value) {
return false;
} else if (value instanceof Set) {
return value.size > 0;
} else if (typeof value == "object") {
return Object.keys(value).length > 0;
} else {
return true;
}
}
/**
* Applies map and filter on an array, using a single function
*/
export function fmap<A, T extends A>(m?: undefined, f?: (val: A) => val is T): (array: A[]) => T[];
export function fmap<A>(m?: undefined, f?: (val: A) => boolean): (array: A[]) => A[];
export function fmap<A, B, T extends B>(m: (val: A) => B, f?: (val: B) => val is T): (array: A[]) => T[];
export function fmap<A, B>(m: (val: A) => B, f?: (val: B) => boolean): (array: A[]) => B[];
export function fmap<A, B>(m?: (val: A) => B, f?: (val: A | B) => boolean): (array: A[]) => (A | B)[] {
return array => {
if (m && f) {
return array.map(m).filter(f);
} else if (m) {
return array.map(m);
} else if (f) {
return array.filter(f);
} else {
return array.slice();
}
};
}