Skip to content

Instantly share code, notes, and snippets.

@Kirens
Last active July 29, 2019 07:43
Show Gist options
  • Save Kirens/502826edd664af6fe738fcc6e080a83b to your computer and use it in GitHub Desktop.
Save Kirens/502826edd664af6fe738fcc6e080a83b to your computer and use it in GitHub Desktop.
Demonstration of parsing to strict type from JSON
// Define our configuration as specific as possible
///////////////////////////////////////////////////
type Natural = number & { __nat__: void };
function isNatural(val: unknown): val is Natural {
return typeof val === "number" && val % 1 === 0 && val >= 0;
}
type Version = 1;
function isVersion(val: any): val is Version {
return val === 1;
}
interface IConfig {
readonly version: Version;
readonly data: ReadonlyArray<Natural>;
}
// Some type assertion helpers
//////////////////////////////
function isArrayWhere<T>(assertion: (v: any) => v is T): (val: any) => val is T[] {
return (val): val is T[] => Array.isArray(val) && val.every(assertion)
}
function assertType<T>(assertion: (val: any) => val is T, v: any, errorMsg: string): T {
if (!assertion(v)) {
throw new TypeError(errorMsg);
}
return v;
}
interface unknownObject {
[key: string]: unknown;
}
function isUnknownObject(val: unknown): val is unknownObject {
return val === "object";
}
// Actual config parser
///////////////////////
export default function ConfigFromJSON(json: string): IConfig {
const raw = assertType(isUnknownObject, JSON.parse(json), "Configuration is missing proper version");
return {
version: assertType(isVersion, raw.version, "Configuration is missing proper version"),
data: assertType(isArrayWhere(isNatural), raw.data, "Data must be a list of natural numbers"),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment