Skip to content

Instantly share code, notes, and snippets.

@DevWurm
Last active December 21, 2016 15:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DevWurm/51b60a678ef5aa561078df34009738c3 to your computer and use it in GitHub Desktop.
Save DevWurm/51b60a678ef5aa561078df34009738c3 to your computer and use it in GitHub Desktop.
A simple generic type matching / constructor matching type guard for type script
// import match.ts
// weired types
class Nums {
a: number = 2
b(): number {
return 7;
}
}
type numeric = number | number[] | Nums
// function for extracting a basic number from a numeric type
function extract(n: numeric): number {
// matching by type constructor
if (match(n, Array)) {
return n[0];
}
// matching by type compliant literal (possible, but not reccomended in favot of readability)
else if (match(n, 7)) {
return n;
}
// matching by type complienat object literal
else if (match(n, { a: 1, b: () => 7 })) {
return n.a + n.b();
}
else {
return NaN;
}
}
alert(`Expecting 7.123: ${extract(7.123)}`);
alert(`Expecting 4: ${extract([4, 3, 2, 1])}`);
alert(`Expecting 9: ${extract(new Nums())}`);
alert(`Expecting 3: ${extract({ a: 0, b: () => 3 })}`);
function match<T>(o: any, ref: {new(...args : any[]): T} | T): o is T {
let oObject: Object;
switch (typeof o) {
case 'boolean': oObject = new Boolean(o); break;
case 'number': oObject = new Number(o); break;
case 'string': oObject = new String(o); break;
case 'undefined': return ref === undefined;
default: oObject = o;
}
if (isConstructor(ref)) {
return (
oObject instanceof ref
||
Object.getOwnPropertyNames(ref.prototype)
.reduce((acc, curr) => (curr in oObject) && acc, true)
)
} else {
return (
Object.getOwnPropertyNames(Object.getPrototypeOf(ref))
.reduce((acc, curr) => (curr in oObject) && acc, true)
)
}
}
function isConstructor<T>(x: { new (...args : any[]): T } | T): x is { new (): T } {
return Boolean((<{ new (): T }> x).prototype);
}

Problems

  • can't decide between different array types (solution idea: if the reference array is not empty, test the first element against the first element of the test element)
@DevWurm
Copy link
Author

DevWurm commented Nov 27, 2016

Live example: http://www.typescriptlang.org/play/index.html#src=function%20match%3CT%3E(o%3A%20any%2C%20ref%3A%20%7Bnew()%3A%20T%7D%20%7C%20T)%3A%20o%20is%20T%20%20%7B%0D%0A%20%20%20%20let%20oObject%3A%20Object%3B%0D%0A%20%20%20%20switch%20(typeof%20o)%20%7B%0D%0A%20%20%20%20%20%20%20%20case%20%27boolean%27%3A%20oObject%20%3D%20new%20Boolean(o)%3B%20break%3B%0D%0A%20%20%20%20%20%20%20%20case%20%27number%27%3A%20oObject%20%3D%20new%20Number(o)%3B%20break%3B%0D%0A%20%20%20%20%20%20%20%20case%20%27string%27%3A%20oObject%20%3D%20new%20String(o)%3B%20break%3B%0D%0A%20%20%20%20%20%20%20%20case%20%27undefined%27%3A%20return%20ref%20%3D%3D%3D%20undefined%3B%0D%0A%20%20%20%20%20%20%20%20default%3A%20oObject%20%3D%20o%3B%0D%0A%20%20%20%20%7D%0D%0A%0D%0A%20%20%20%20if%20(isConstructor(ref))%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20(%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20oObject%20instanceof%20ref%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7C%7C%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20Object.getOwnPropertyNames(ref.prototype)%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.reduce((acc%2C%20curr)%20%3D%3E%20(curr%20in%20oObject)%20%26%26%20acc%2C%20true)%0D%0A%20%20%20%20%20%20%20%20)%0D%0A%20%20%20%20%7D%20else%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20(%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20Object.getOwnPropertyNames(Object.getPrototypeOf(ref))%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.reduce((acc%2C%20curr)%20%3D%3E%20(curr%20in%20oObject)%20%26%26%20acc%2C%20true)%0D%0A%20%20%20%20%20%20%20%20)%0D%0A%20%20%20%20%7D%0D%0A%0D%0A%7D%0D%0A%0D%0Afunction%20isConstructor%3CT%3E(x%3A%20%7B%20new%20()%3A%20T%20%7D%20%7C%20T)%3A%20x%20is%20%7B%20new%20()%3A%20T%20%7D%20%7B%0D%0A%20%20%20%20return%20Boolean((%3C%7B%20new%20()%3A%20T%20%7D%3E%20x).prototype)%3B%0D%0A%7D%0D%0A%0D%0A%2F%2F%20weired%20types%0D%0Aclass%20Nums%20%7B%0D%0A%20%20%20%20a%3A%20number%20%3D%202%0D%0A%20%20%20%20b()%3A%20number%20%7B%0D%0A%20%20%20%20%20%20%20%20return%207%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0Atype%20numeric%20%3D%20number%20%7C%20number%5B%5D%20%7C%20Nums%0D%0A%0D%0A%2F%2F%20function%20for%20extracting%20a%20basic%20number%20from%20a%20numeric%20type%0D%0Afunction%20extract(n%3A%20numeric)%3A%20number%20%7B%0D%0A%20%20%20%20%2F%2F%20matching%20by%20type%20constructor%0D%0A%20%20%20%20if%20(match(n%2C%20Array))%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20n%5B0%5D%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%20%20%2F%2F%20matching%20by%20type%20compliant%20literal%20(possible%2C%20but%20not%20reccomended%20in%20favot%20of%20readability)%0D%0A%20%20%20%20else%20if%20(match(n%2C%207))%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20n%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%20%20%2F%2F%20matching%20by%20type%20complienat%20object%20literal%0D%0A%20%20%20%20else%20if%20(match(n%2C%20%7B%20a%3A%201%2C%20b%3A%20()%20%3D%3E%207%20%7D))%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20n.a%20%2B%20n.b()%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%20%20else%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20NaN%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0Aalert(%60Expecting%207.123%3A%20%24%7Bextract(7.123)%7D%60)%3B%0D%0Aalert(%60Expecting%204%3A%20%24%7Bextract(%5B4%2C%203%2C%202%2C%201%5D)%7D%60)%3B%0D%0Aalert(%60Expecting%209%3A%20%24%7Bextract(new%20Nums())%7D%60)%3B%0D%0Aalert(%60Expecting%203%3A%20%24%7Bextract(%7B%20a%3A%200%2C%20b%3A%20()%20%3D%3E%203%20%7D)%7D%60)%3B

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