Skip to content

Commit 74fd7fb

Browse files
committed
Add maybe
1 parent 7c88373 commit 74fd7fb

File tree

3 files changed

+371
-0
lines changed

3 files changed

+371
-0
lines changed

maybe.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {
2+
isArray,
3+
isBoolean,
4+
isFunction,
5+
isLike,
6+
isNumber,
7+
isObject,
8+
isString,
9+
Predicate,
10+
} from "./is.ts";
11+
12+
function maybe<T>(
13+
x: unknown,
14+
pred: Predicate<T>,
15+
): T | undefined {
16+
if (!pred(x)) {
17+
return;
18+
}
19+
return x;
20+
}
21+
22+
/**
23+
* Return `x` as-is if the type of the value is string or `undefined` if not.
24+
*/
25+
export function maybeString(x: unknown): string | undefined {
26+
return maybe(x, isString);
27+
}
28+
29+
/**
30+
* Return `x` as-is if the type of the value is number or `undefined` if not.
31+
*/
32+
export function maybeNumber(x: unknown): number | undefined {
33+
return maybe(x, isNumber);
34+
}
35+
36+
/**
37+
* Return `x` as-is if the type of the value is boolean or `undefined` if not.
38+
*/
39+
export function maybeBoolean(x: unknown): boolean | undefined {
40+
return maybe(x, isBoolean);
41+
}
42+
43+
/**
44+
* Return `x` as-is if the type of the value is array or `undefined` if not.
45+
*/
46+
export function maybeArray<T extends unknown>(
47+
x: unknown,
48+
ipred?: Predicate<T>,
49+
): T[] | undefined {
50+
const pred = (x: unknown): x is T[] => isArray(x, ipred);
51+
return maybe(x, pred);
52+
}
53+
54+
/**
55+
* Return `x` as-is if the type of the value is object or `undefined` if not.
56+
*/
57+
export function maybeObject<T>(
58+
x: unknown,
59+
ipred?: Predicate<T>,
60+
): Record<string, T> | undefined {
61+
const pred = (x: unknown): x is Record<string, T> => isObject(x, ipred);
62+
return maybe(x, pred);
63+
}
64+
65+
/**
66+
* Return `x` as-is if the type of the value is function or `undefined` if not.
67+
*/
68+
export function maybeFunction(
69+
x: unknown,
70+
): ((...args: unknown[]) => unknown) | undefined {
71+
return maybe(x, isFunction);
72+
}
73+
74+
/**
75+
* Return `x` as-is if the type of the value follow the reference or `undefined` if not.
76+
*/
77+
export function maybeLike<R, T extends unknown>(
78+
ref: R,
79+
x: unknown,
80+
ipred?: Predicate<T>,
81+
): R | undefined {
82+
const pred = (x: unknown): x is R => isLike(ref, x, ipred);
83+
return maybe(x, pred);
84+
}

maybe_test.ts

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
import { assertEquals } from "./deps_test.ts";
2+
import { assertUndefined } from "./assert.ts";
3+
import {
4+
maybeArray,
5+
maybeBoolean,
6+
maybeFunction,
7+
maybeLike,
8+
maybeNumber,
9+
maybeObject,
10+
maybeString,
11+
} from "./maybe.ts";
12+
import { isBoolean, isNumber, isString } from "./is.ts";
13+
14+
Deno.test("maybeString returns the value when the value is string", () => {
15+
assertEquals(maybeString("Hello"), "Hello");
16+
});
17+
Deno.test("maybeString returns undefined on non string", () => {
18+
assertUndefined(maybeString(0));
19+
assertUndefined(maybeString(true));
20+
assertUndefined(maybeString(false));
21+
assertUndefined(maybeString([]));
22+
assertUndefined(maybeString({}));
23+
assertUndefined(maybeString(function () {}));
24+
assertUndefined(maybeString(undefined));
25+
assertUndefined(maybeString(null));
26+
});
27+
28+
Deno.test("maybeNumber returns the value when the value is number", () => {
29+
assertEquals(maybeNumber(0), 0);
30+
assertEquals(maybeNumber(1), 1);
31+
assertEquals(maybeNumber(0.1), 0.1);
32+
});
33+
Deno.test("maybeNumber returns undefined on non number", () => {
34+
assertUndefined(maybeNumber("a"));
35+
assertUndefined(maybeNumber(true));
36+
assertUndefined(maybeNumber(false));
37+
assertUndefined(maybeNumber([]));
38+
assertUndefined(maybeNumber({}));
39+
assertUndefined(maybeNumber(function () {}));
40+
assertUndefined(maybeNumber(undefined));
41+
assertUndefined(maybeNumber(null));
42+
});
43+
44+
Deno.test("maybeBoolean returns the value when the value is boolean", () => {
45+
assertEquals(maybeBoolean(true), true);
46+
assertEquals(maybeBoolean(false), false);
47+
});
48+
Deno.test("maybeBoolean returns undefined on non boolean", () => {
49+
assertUndefined(maybeBoolean(0));
50+
assertUndefined(maybeBoolean("a"));
51+
assertUndefined(maybeBoolean([]));
52+
assertUndefined(maybeBoolean({}));
53+
assertUndefined(maybeBoolean(function () {}));
54+
assertUndefined(maybeBoolean(undefined));
55+
assertUndefined(maybeBoolean(null));
56+
});
57+
58+
Deno.test("maybeArray returns the value when the value is array", () => {
59+
assertEquals(maybeArray([]), []);
60+
assertEquals(maybeArray([0, 1, 2]), [0, 1, 2]);
61+
assertEquals(maybeArray(["a", "b", "c"]), ["a", "b", "c"]);
62+
});
63+
Deno.test("maybeArray returns undefined on non array", () => {
64+
assertUndefined(maybeArray("a"));
65+
assertUndefined(maybeArray(0));
66+
assertUndefined(maybeArray(true));
67+
assertUndefined(maybeArray(false));
68+
assertUndefined(maybeArray({}));
69+
assertUndefined(maybeArray(function () {}));
70+
assertUndefined(maybeArray(undefined));
71+
assertUndefined(maybeArray(null));
72+
});
73+
Deno.test("maybeArray<T> returns the value when the value is T array", () => {
74+
assertEquals(maybeArray([0, 1, 2], isNumber), [0, 1, 2]);
75+
assertEquals(maybeArray(["a", "b", "c"], isString), ["a", "b", "c"]);
76+
assertEquals(maybeArray([true, false, true], isBoolean), [
77+
true,
78+
false,
79+
true,
80+
]);
81+
});
82+
Deno.test("maybeArray<T> returns undefined on non T array", () => {
83+
assertUndefined(maybeArray([0, 1, 2], isString));
84+
assertUndefined(maybeArray(["a", "b", "c"], isNumber));
85+
assertUndefined(maybeArray([true, false, true], isString));
86+
});
87+
88+
Deno.test("maybeObject return the value when the value is object", () => {
89+
assertEquals(maybeObject({}), {});
90+
assertEquals(maybeObject({ a: 0 }), { a: 0 });
91+
assertEquals(maybeObject({ a: "a" }), { a: "a" });
92+
});
93+
Deno.test("maybeObject returns undefined on non object", () => {
94+
assertUndefined(maybeObject("a"));
95+
assertUndefined(maybeObject(0));
96+
assertUndefined(maybeObject(true));
97+
assertUndefined(maybeObject(false));
98+
assertUndefined(maybeObject([]));
99+
assertUndefined(maybeObject(function () {}));
100+
assertUndefined(maybeObject(undefined));
101+
assertUndefined(maybeObject(null));
102+
});
103+
Deno.test(
104+
"maybeObject<T> returns the value when the value is T object",
105+
() => {
106+
assertEquals(maybeObject({ a: 0 }, isNumber), { a: 0 });
107+
assertEquals(maybeObject({ a: "a" }, isString), { a: "a" });
108+
assertEquals(maybeObject({ a: true }, isBoolean), { a: true });
109+
},
110+
);
111+
Deno.test("maybeObject<T> returns undefined on non T object", () => {
112+
assertUndefined(maybeObject({ a: 0 }, isString));
113+
assertUndefined(maybeObject({ a: "a" }, isNumber));
114+
assertUndefined(maybeObject({ a: true }, isString));
115+
});
116+
117+
Deno.test("maybeFunction returns the value when the value is function", () => {
118+
assertEquals(maybeFunction(maybeFunction), maybeFunction);
119+
const a = function () {};
120+
assertEquals(maybeFunction(a), a);
121+
const b = () => {};
122+
assertEquals(maybeFunction(b), b);
123+
assertEquals(maybeFunction(setTimeout), setTimeout);
124+
});
125+
Deno.test("maybeFunction returns undefined on non function", () => {
126+
assertUndefined(maybeFunction("a"));
127+
assertUndefined(maybeFunction(0));
128+
assertUndefined(maybeFunction(true));
129+
assertUndefined(maybeFunction(false));
130+
assertUndefined(maybeFunction([]));
131+
assertUndefined(maybeFunction({}));
132+
assertUndefined(maybeFunction(undefined));
133+
assertUndefined(maybeFunction(null));
134+
});
135+
136+
Deno.test("maybeLike does it's job on string", () => {
137+
const ref = "";
138+
assertEquals(maybeLike(ref, "Hello"), "Hello");
139+
140+
assertUndefined(maybeLike(ref, 0));
141+
assertUndefined(maybeLike(ref, true));
142+
assertUndefined(maybeLike(ref, false));
143+
assertUndefined(maybeLike(ref, []));
144+
assertUndefined(maybeLike(ref, {}));
145+
assertUndefined(maybeLike(ref, function () {}));
146+
assertUndefined(maybeLike(ref, undefined));
147+
assertUndefined(maybeLike(ref, null));
148+
});
149+
Deno.test("maybeLike does it's job on number", () => {
150+
const ref = 0;
151+
assertEquals(maybeLike(ref, 0), 0);
152+
assertEquals(maybeLike(ref, 1), 1);
153+
assertEquals(maybeLike(ref, 0.1), 0.1);
154+
155+
assertUndefined(maybeLike(ref, "a"));
156+
assertUndefined(maybeLike(ref, true));
157+
assertUndefined(maybeLike(ref, false));
158+
assertUndefined(maybeLike(ref, []));
159+
assertUndefined(maybeLike(ref, {}));
160+
assertUndefined(maybeLike(ref, function () {}));
161+
assertUndefined(maybeLike(ref, undefined));
162+
assertUndefined(maybeLike(ref, null));
163+
});
164+
Deno.test("maybeLike does it's job on array", () => {
165+
const ref: unknown[] = [];
166+
assertEquals(maybeLike(ref, []), []);
167+
assertEquals(maybeLike(ref, [0, 1, 2]), [0, 1, 2]);
168+
assertEquals(maybeLike(ref, ["a", "b", "c"]), ["a", "b", "c"]);
169+
170+
assertUndefined(maybeLike(ref, "a"));
171+
assertUndefined(maybeLike(ref, 0));
172+
assertUndefined(maybeLike(ref, {}));
173+
assertUndefined(maybeLike(ref, function () {}));
174+
assertUndefined(maybeLike(ref, undefined));
175+
assertUndefined(maybeLike(ref, null));
176+
});
177+
Deno.test("maybeLike does it's job on T array", () => {
178+
const ref: unknown[] = [];
179+
assertEquals(maybeLike(ref, [0, 1, 2], isNumber), [0, 1, 2]);
180+
assertEquals(maybeLike(ref, ["a", "b", "c"], isString), ["a", "b", "c"]);
181+
assertEquals(maybeLike(ref, [true, false, true], isBoolean), [
182+
true,
183+
false,
184+
true,
185+
]);
186+
187+
assertUndefined(maybeLike(ref, [0, 1, 2], isString));
188+
assertUndefined(maybeLike(ref, ["a", "b", "c"], isNumber));
189+
assertUndefined(maybeLike(ref, [true, false, true], isString));
190+
});
191+
Deno.test("maybeLike does it's job on tuple", () => {
192+
const ref = ["", 0, ""];
193+
assertEquals(maybeLike(ref, ["", 0, ""]), ["", 0, ""]);
194+
assertEquals(maybeLike(ref, ["Hello", 100, "World"]), [
195+
"Hello",
196+
100,
197+
"World",
198+
]);
199+
200+
assertUndefined(maybeLike(ref, ["Hello", 100, "World", "foo"]));
201+
assertUndefined(maybeLike(ref, [0, 0, 0]));
202+
assertUndefined(maybeLike(ref, ["", "", ""]));
203+
assertUndefined(maybeLike(ref, [0, "", 0]));
204+
});
205+
Deno.test("maybeLike does it's job on object", () => {
206+
const ref = {};
207+
assertEquals(maybeLike(ref, {}), {});
208+
assertEquals(maybeLike(ref, { a: 0 }), { a: 0 });
209+
assertEquals(maybeLike(ref, { a: "a" }), { a: "a" });
210+
211+
assertUndefined(maybeLike(ref, "a"));
212+
assertUndefined(maybeLike(ref, 0));
213+
assertUndefined(maybeLike(ref, true));
214+
assertUndefined(maybeLike(ref, false));
215+
assertUndefined(maybeLike(ref, []));
216+
assertUndefined(maybeLike(ref, function () {}));
217+
assertUndefined(maybeLike(ref, undefined));
218+
assertUndefined(maybeLike(ref, null));
219+
});
220+
Deno.test("maybeLike does it's job on T object", () => {
221+
const ref = {};
222+
assertEquals(maybeLike(ref, { a: 0 }, isNumber), { a: 0 });
223+
assertEquals(maybeLike(ref, { a: "a" }, isString), { a: "a" });
224+
assertEquals(maybeLike(ref, { a: true }, isBoolean), { a: true });
225+
226+
assertUndefined(maybeLike(ref, { a: 0 }, isString));
227+
assertUndefined(maybeLike(ref, { a: "a" }, isNumber));
228+
assertUndefined(maybeLike(ref, { a: true }, isString));
229+
});
230+
Deno.test("maybeLike does it's job on struct", () => {
231+
const ref = { foo: "", bar: 0 };
232+
assertEquals(maybeLike(ref, { foo: "", bar: 0 }), { foo: "", bar: 0 });
233+
assertEquals(maybeLike(ref, { foo: "", bar: 0, hoge: "" }), {
234+
foo: "",
235+
bar: 0,
236+
hoge: "",
237+
});
238+
239+
assertUndefined(maybeLike(ref, {}));
240+
assertUndefined(maybeLike(ref, { foo: "" }));
241+
assertUndefined(maybeLike(ref, { bar: 0 }));
242+
});
243+
Deno.test("maybeLike does it's job on function", () => {
244+
const ref = () => {};
245+
assertEquals(maybeLike(ref, maybeFunction), maybeFunction);
246+
const a = function () {};
247+
assertEquals(maybeLike(ref, a), a);
248+
const b = () => {};
249+
assertEquals(maybeLike(ref, b), b);
250+
assertEquals(maybeLike(ref, setTimeout), setTimeout);
251+
252+
assertUndefined(maybeLike(ref, "a"));
253+
assertUndefined(maybeLike(ref, 0));
254+
assertUndefined(maybeLike(ref, true));
255+
assertUndefined(maybeLike(ref, false));
256+
assertUndefined(maybeLike(ref, []));
257+
assertUndefined(maybeLike(ref, {}));
258+
assertUndefined(maybeLike(ref, undefined));
259+
assertUndefined(maybeLike(ref, null));
260+
});
261+
Deno.test("maybeLike does it's job on null", () => {
262+
const ref = null;
263+
assertEquals(maybeLike(ref, null), null);
264+
265+
assertUndefined(maybeLike(ref, "a"));
266+
assertUndefined(maybeLike(ref, 0));
267+
assertUndefined(maybeLike(ref, true));
268+
assertUndefined(maybeLike(ref, false));
269+
assertUndefined(maybeLike(ref, []));
270+
assertUndefined(maybeLike(ref, {}));
271+
assertUndefined(maybeLike(ref, function () {}));
272+
assertUndefined(maybeLike(ref, undefined));
273+
});
274+
Deno.test("maybeLike does it's job on undefined", () => {
275+
const ref = undefined;
276+
assertEquals(maybeLike(ref, undefined), undefined);
277+
278+
assertUndefined(maybeLike(ref, "a"));
279+
assertUndefined(maybeLike(ref, 0));
280+
assertUndefined(maybeLike(ref, true));
281+
assertUndefined(maybeLike(ref, false));
282+
assertUndefined(maybeLike(ref, []));
283+
assertUndefined(maybeLike(ref, {}));
284+
assertUndefined(maybeLike(ref, function () {}));
285+
assertUndefined(maybeLike(ref, null));
286+
});

mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./assert.ts";
22
export * from "./ensure.ts";
33
export * from "./is.ts";
4+
export * from "./maybe.ts";

0 commit comments

Comments
 (0)