@unsplash/sum-types
Version:
Safe, ergonomic, non-generic sum types in TypeScript.
68 lines (67 loc) • 2.09 kB
JavaScript
const tagKey = Symbol("@unsplash/sum-types internal tag key");
const valueKey = Symbol("@unsplash/sum-types internal value key");
export const mkConstructor = () => (k) => {
const nonNullary = (v => ({
[tagKey]: k,
[valueKey]: v,
}));
const nullary = nonNullary(null);
return Object.assign(nonNullary, nullary);
};
const mkConstructors = () => {
const xs = new Map();
return new Proxy({}, {
get: (__, tag) => {
const f = xs.get(tag);
if (f !== undefined)
return f;
const g = mkConstructor()(tag);
xs.set(tag, g);
return g;
},
});
};
export const _ = Symbol("@unsplash/sum-types pattern matching wildcard");
const mkMatchW = () => (fs) => (x) => {
const tag = x[tagKey];
const g = fs[tag];
if (g !== undefined)
return g(x[valueKey]);
const h = fs[_];
if (h !== undefined)
return h();
throw new Error(`Failed to pattern match against tag "${tag}".`);
};
const mkMatchXW = () => (fs) => (x) => {
const tag = x[tagKey];
if (Object.prototype.hasOwnProperty.call(fs, tag))
return fs[tag];
if (Object.prototype.hasOwnProperty.call(fs, _))
return fs[_];
throw new Error(`Failed to pattern match against tag "${tag}".`);
};
const mkMatch = () => (fs) => (x) => mkMatchW()(fs)(x);
const mkMatchX = () => (fs) => (x) => mkMatchXW()(fs)(x);
export const create = () => ({
mk: mkConstructors(),
match: mkMatch(),
matchW: mkMatchW(),
matchX: mkMatchX(),
matchXW: mkMatchXW(),
});
export const serialize = (x) => [x[tagKey], x[valueKey]];
export const deserialize = (x) => (y) => {
const k = y[0];
const v = y[1];
return v === null ? x.mk[k] : x.mk[k](v);
};
export const is = () => (k) => (f) => (x) => {
if (x === null || !["object", "function"].includes(typeof x))
return false;
const xx = x;
if (!(tagKey in xx) || xx[tagKey] !== k)
return false;
if (!(valueKey in xx) || !f(xx[valueKey]))
return false;
return true;
};