Created
September 22, 2015 12:13
-
-
Save uniphil/36c5d750fd7a1cf704a5 to your computer and use it in GitHub Desktop.
Type-checked hard-coded results match API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface Matchable { | |
name: string; | |
data: any[]; | |
match: (options: ProjectActionMatcher) => any; | |
} | |
interface MatcherCatchAll { | |
_: (...args: any[]) => any; | |
} | |
interface ProjectActionMatcher { | |
Reset: () => any; | |
Select: (id: string) => any; | |
Hover: (id: string) => any; | |
Rename: (id: string, newName: string) => any; | |
} | |
function hasProp(obj: any, prop: string): void { | |
} | |
class ProjectActionClass { | |
static options = {Reset: 1, Select: 1, Hover: 1, Rename: 1}; | |
name; | |
data; | |
constructor(...args: any[]) { | |
this.data = args; | |
} | |
match(options: ProjectActionMatcher|MatcherCatchAll) { | |
if (!options.hasOwnProperty('_')) { // no _: not catch-all, already typechecked | |
return options[this.name](...this.data); | |
} else { // has a catch-all, so lets first check all the keys | |
for (const o in options) { | |
if (options.hasOwnProperty(o) && o !== '_') { | |
if (typeof options[o] !== 'function') { | |
// Every value of `options` must be a function | |
throw new Error(`options value for option ${o} is a ` + | |
`${typeof options[o]} but should be a function`); | |
} | |
} | |
} | |
if (typeof options[this.name] === 'undefined') { | |
// not us, do the catch-all | |
return (<MatcherCatchAll>options)._(this); | |
} else { | |
return options[this.name](...this.data); | |
} | |
} | |
} | |
} | |
class ResetOption extends ProjectActionClass { name = 'Reset'; } | |
class SelectOption extends ProjectActionClass { name = 'Select'; } | |
class HoverOption extends ProjectActionClass { name = 'Hover'; } | |
class RenameOption extends ProjectActionClass { name = 'Rename'; } | |
const ProjectAction = { | |
Reset: () => new ResetOption(), | |
Select: (id) => new SelectOption(id), | |
Hover: (id) => new HoverOption(id), | |
Rename: (id, newName) => new RenameOption(id, newName), | |
}; | |
ProjectAction.Reset().match({ | |
Reset: () => console.log(`Reset`), | |
Select: (id) => console.log(`Select: ${id}`), | |
Hover: (id) => console.log(`Hover: ${id}`), | |
Rename: (id, newName) => console.log(`Rename: ${id} ${newName}`), | |
}); | |
// should fail: bad option arg: | |
ProjectAction.Reset('z').match({ | |
Reset: () => console.log(`Reset`), | |
Select: (id) => console.log(`Select: ${id}`), | |
Hover: (id) => console.log(`Hover: ${id}`), | |
Rename: (id, newName) => console.log(`Rename: ${id} ${newName}`), | |
}); | |
// // Should fail: missing option: | |
// ProjectAction.Reset().match({ | |
// Reset: () => console.log(`Reset`), | |
// Select: (id) => console.log(`Select: ${id}`), | |
// Hover: (id) => console.log(`Hover: ${id}`), | |
// }); | |
ProjectAction.Select('sup').match({ | |
Reset: () => console.log(`Reset`), | |
Select: (id) => console.log(`Select: ${id}`), | |
Hover: (id) => console.log(`Hover: ${id}`), | |
Rename: (id, newName) => console.log(`Rename: ${id} ${newName}`), | |
}); | |
// // should fail: missing option arg: | |
// ProjectAction.Select().match({ | |
// Reset: () => console.log(`Reset`), | |
// Select: (id) => console.log(`Select: ${id}`), | |
// Hover: (id) => console.log(`Hover: ${id}`), | |
// Rename: (id, newName) => console.log(`Rename: ${id} ${newName}`), | |
// }); | |
ProjectAction.Reset().match({ | |
Reset: () => console.log(`Reset (not wild)`), | |
_: (option) => console.log(`wild!: ${option.data}`), | |
}); | |
ProjectAction.Rename('z', 'something else').match({ | |
Reset: () => console.log(`Reset (not wild)`), | |
_: (option) => console.log(`wild! ${option.name} with ${option.data}`), | |
}); | |
// // should fail at runtime: non-function branch | |
// ProjectAction.Rename('z', 'something else').match({ | |
// Reset: null, | |
// _: (option) => console.log(`should not get here`), | |
// }); | |
// // should fail at compile time: bad option name (wooooo union types!) | |
// ProjectAction.Rename('z', 'something else').match({ | |
// BadOptionName: () => null, | |
// _: (option) => console.log(`should not get here`), | |
// }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment