/** * @tsplus type Case.Ops */ export interface CaseOps { of: () => Case.Constructor tagged: (tag: A["_tag"]) => Case.Constructor } export const Case: CaseOps = { of: () => // @ts-expect-error (args) => { const obj = { [Hash.sym]: hashImpl, [Equals.sym]: equalsImpl, [Copy.sym]: copyImpl } for (const k of Object.keys(args)) { if (typeof args[k] !== "undefined") { obj[k] = args[k] } } return obj }, tagged: (tag) => // @ts-expect-error (args) => { const obj = { [Hash.sym]: hashImpl, [Equals.sym]: equalsImpl, [Copy.sym]: copyImpl, _tag: tag } for (const k of Object.keys(args)) { if (typeof args[k] !== "undefined") { obj[k] = args[k] } } return obj } } function copyImpl(this: A, that: Partial): A { const obj = { [Hash.sym]: hashImpl, [Equals.sym]: equalsImpl, [Copy.sym]: copyImpl } for (const k of Object.keys(this)) { if (typeof this[k] !== "undefined") { obj[k] = this[k] } } for (const k of Object.keys(that)) { if (typeof that[k] !== "undefined") { obj[k] = that[k] } else { delete obj[k] } } // @ts-expect-error return obj } function equalsImpl(this: A, that: Partial): boolean { const keysA = Object.keys(this) const keysB = Object.keys(that) if (keysA.length !== keysB.length) { return false } for (const key of keysA) { if (!Equals.equals(this[key], that[key])) { return false } } return true } function hashImpl(this: A): number { return Hash.plainObject(this) } /** * @tsplus type Case */ export interface Case extends Equals, Copy { } export declare namespace Case { export interface Constructor { (args: Omit): A } }