Created
November 10, 2016 19:13
-
-
Save rob3c/28c8264c045fc4ce4eff6cf45cd81551 to your computer and use it in GitHub Desktop.
TypeScript pattern matching proof-of-concept
This file contains 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