Last active
February 3, 2021 07:22
-
-
Save patrixr/da8e41b5f3fa552a0a44bb1ee1b11e5d to your computer and use it in GitHub Desktop.
Lodash & Typescript pattern matching
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
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