-
-
Save josgraha/8ac4c7d96f638f5aff9a3d23ae1443d1 to your computer and use it in GitHub Desktop.
TypeScript pattern matching proof-of-concept
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
// preserved from my comment in this issue: https://github.com/Microsoft/TypeScript/issues/165#issuecomment-259598080 | |
interface Type<T> { new(...args): T } | |
interface CaseResult<R> { | |
success: boolean; | |
result: R; | |
} | |
interface CaseFn<R> { (value: any): CaseResult<R> } | |
function Case<R>(t: number, p: (n: number) => R): CaseFn<R>; | |
function Case<R>(t: string, p: (s: string) => R): CaseFn<R>; | |
function Case<T, R>(t: Type<T>, p: (t: T) => R): CaseFn<R>; | |
function Case<R>(t: boolean, p: () => R): CaseFn<R>; | |
function Case<R>(type: any, project: (t: any) => R): CaseFn<R> { | |
return (a) => { | |
const success = !!a && ( | |
typeof type === 'function' && a instanceof type || | |
typeof type === 'boolean' && type || | |
typeof type === typeof a && type === a | |
); | |
const result = success && project(a); | |
return { success, result }; | |
} | |
} | |
function DefaultCase<R>(value: R): CaseFn<R> { | |
return (_) => ({ success: true, result: value }); | |
} | |
function match<A, R>(a: A, ...cases: CaseFn<R>[]): R { | |
for (var i = 0; i < cases.length; i++) { | |
const r = cases[i](a); | |
if (r.success) { | |
return r.result; | |
} | |
} | |
return undefined; | |
} | |
class Foo { constructor(public s: string, public n: number) { } } | |
class Bar { constructor(public n: number, public foo: Foo) { } } | |
class Baz { constructor(public s: string, public bar: Bar) { } } | |
function testMatch(a: any): number { | |
return match(a, | |
Case(Foo, f => f.n), | |
Case(Bar, b => b.foo.n), | |
Case(23, n => n + 1), | |
Case('asdf', s => s.length), | |
Case(a + 1 === 2, () => 2), | |
DefaultCase(-1) | |
); | |
} | |
let foo = new Foo('foo', 1); | |
let bar = new Bar(2, foo); | |
let baz = new Baz('baz', bar); | |
alert('foo: ' + testMatch(foo)); // 1 | |
alert('bar: ' + testMatch(bar)); // 2 | |
alert('baz: ' + testMatch(baz)); // -1 | |
alert('23: ' + testMatch(23)); // 24 | |
alert('asdf: ' + testMatch('asdf')); // 4 | |
alert('a + 1: ' + testMatch(1)); // 2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment