Skip to content

Instantly share code, notes, and snippets.

@wkronemeijer
Last active June 18, 2016 17:53
Show Gist options
  • Save wkronemeijer/ca9d0f660c44624364ad4b690a01db17 to your computer and use it in GitHub Desktop.
Save wkronemeijer/ca9d0f660c44624364ad4b690a01db17 to your computer and use it in GitHub Desktop.
ES6 Module for creating what can be considered **almost** ADTs.
export interface InstanceConstructor<
/**Enum */ E,
/**Shared properties */ S,
/**Unique properties */ T
> {
/**Create new instance */
(diffs?: S & T): S & T;
/**Type guard for destructuring */
typecheck(object: {}): object is S & T;
/**For introspection, and to make IntelliSense work */
Kind: E;
}
export interface CaseConstructor<E, S> {
/**Use `Instance` to create a type alias for the enum */
Instance: S;
/**Create a new case for the `Enum` */
Case<T>(member: E, template: T): InstanceConstructor<E, S, T>;
}
const _EnumSymbol = Symbol('enum');
const _CaseSymbol = Symbol('case');
export function Enum<E, S>(
/**Host `enum` for names and IDs */ enum_: {},
/**`enum` member to help IntelliSense */ any_member: E,
/**Properties common to all `Case`s */ common_properties: S
): CaseConstructor<E, S> {
return {
Instance: common_properties,
Case<T>(member: E, template: T): InstanceConstructor<E, S, T> {
template[_EnumSymbol] = enum_;
template[_CaseSymbol] = +member;
template[Symbol.toStringTag] = enum_[+member] as string;
const create = (diffs?: S & T) => Object.assign({}, common_properties, template, diffs);
const helper = {
Kind: member,
typecheck(object: {}): object is S & T {
return (
template[_EnumSymbol] === object[_EnumSymbol] &&
template[_CaseSymbol] === object[_CaseSymbol]
);
},
};
return Object.assign(create, helper);
},
};
}
@wkronemeijer
Copy link
Author

wkronemeijer commented May 17, 2016

Example:

// Step 1
enum ColorKind {
    RGBA, HSLA,

    /* @internal */
    _Self = -1
}

// Step 2
let Color = Enum(ColorKind, ColorKind._Self, {
    alpha: 0,
});
type Color = typeof Color.Instance;

// Step 3
let RGBA = Color.Case(ColorKind.RGBA, {
    red: 0, green: 0, blue: 0,
});

let HSLA = Color.Case(ColorKind.HSLA, {
    hue: 0, saturation: 0, lightness: 0,
});


let electric_seafoam = RGBA({
    red: 37, 
    green: 231,
    blue: 199, 
    alpha: 1,
});

let electric_salmon = HSLA({
    hue: 6,
    saturation: 93 / 100,
    lightness: 58 / 100, 
    alpha: 1,
});


for (let color of [electric_salmon, electric_seafoam]) {
    if (HSLA.typecheck(color)) {
        console.log(color.hue);
    } else if (RGBA.typecheck(color)) {
        console.log(color.red);
    }

    console.log(color.alpha);
}

@wkronemeijer
Copy link
Author

Why use this: your ADTs typecheck and you can use IntelliSense on instance members

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment