Skip to content

Instantly share code, notes, and snippets.

@patrixr
Last active February 3, 2021 07:22
Show Gist options
  • Save patrixr/da8e41b5f3fa552a0a44bb1ee1b11e5d to your computer and use it in GitHub Desktop.
Save patrixr/da8e41b5f3fa552a0a44bb1ee1b11e5d to your computer and use it in GitHub Desktop.
Lodash & Typescript pattern matching
import _, { LoDashStatic } from 'lodash'
type PredicateMethod = (
"has" |
"isEqual" |
"isString" |
"isObject" |
"isArray" |
"isBoolean" |
"isMatch"
) & keyof LoDashStatic
// -----------------------------
// Type definitions
// -----------------------------
type AnyFunction = (...args: any[]) => any;
type ArgumentsOf<F extends AnyFunction> = F extends (...args: infer A) => any ? A : never;
type WhenPredicate<T> = (el: T) => boolean
type ValueResolver<In, Out> = ((el: In) => Out)
type MatchCondition<In, Out> = [WhenPredicate<In>, ValueResolver<In, Out>]|ValueResolver<In, Out>
type Matcher<In, Out> = (el: In) => Out|null
type Tail<T> = T extends [any, ...infer U] ? U : any[]
type TailArgs<F extends AnyFunction> = Tail<ArgumentsOf<F>>
// -----------------------------
// Pattern Matching API
// -----------------------------
export function when<T, M extends PredicateMethod>(
method: M,
...args: TailArgs<LoDashStatic[typeof method]>
) : WhenPredicate<T> {
return (el : T) => Boolean((_ as any)[method](...args))
}
export function matcher<In, Out>(...args: MatchCondition<In, Out>[]) : Matcher<In, Out> {
return (el: In) => {
for (let matcher of args) {
const predicate = _.isArray(matcher) ? matcher[0] : () => true
const resolver = _.isArray(matcher) ? matcher[1] : matcher
if (predicate(el)) {
return resolver(el);
}
}
return null;
}
}
// -----------------------------
// EXAMPLE
// -----------------------------
const guessErrorType = matcher(
[when("has", "body.errors"), () => "ApiError"],
[when("isString"), () => "ServerError"],
[when("isMatch", { message: "unknown error" }), () => "UnknownError"],
() => "Internal Error" // default
)
const errorType = guessErrorType(new Error("unknown error"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment