Skip to content

Instantly share code, notes, and snippets.

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