UNPKG

@unsplash/sum-types

Version:

Safe, ergonomic, non-generic sum types in TypeScript.

68 lines (67 loc) 2.09 kB
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; };