Last active
February 5, 2022 14:46
-
-
Save Lucifier129/8bbf8e3f1c780dab8f1071b47aca1dd3 to your computer and use it in GitHub Desktop.
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
// library | |
type Handler<T, R> = [new (...args: any) => T, (input: T) => R]; | |
type HandlerPattern<T extends Handler<any, any>> = T extends Handler< | |
infer Pattern, | |
any | |
> | |
? Pattern | |
: unknown; | |
type HandlerOutput<T extends Handler<any, any>> = T extends Handler< | |
any, | |
infer Output | |
> | |
? Output | |
: unknown; | |
type Handlers<T> = Handler<any, T>[]; | |
type HandlersOutput<T extends Handlers<any>> = T extends Handlers<infer R> | |
? R | |
: unknown; | |
type UniquePattern<T, HS extends Handlers<any>> = T extends HandlerPattern< | |
HS[number] | |
> | |
? never | |
: T; | |
class Match<T extends Handlers<any>> { | |
input: unknown; | |
patterns: T; | |
constructor(input: unknown, patterns: T) { | |
this.input = input; | |
this.patterns = patterns; | |
} | |
case<U, R extends HandlersOutput<T>>( | |
Ctor: new (...args: any) => UniquePattern<U, T>, | |
handler: (data: U) => R | |
): Match<[...T, Handler<U, R>]> { | |
return new Match(this.input, [...this.patterns, [Ctor, handler]]); | |
} | |
default<R extends HandlersOutput<T>>( | |
handler: (input: unknown) => R | |
): HandlersOutput<T> { | |
for (const [Ctor, handler] of this.patterns) { | |
if (this.input instanceof Ctor) { | |
return handler(this.input); | |
} | |
} | |
return handler(this.input); | |
} | |
} | |
const match = (input: unknown): Match<[]> => { | |
return new Match(input, []); | |
}; | |
// email example | |
abstract class BaseEmail { | |
value: string; | |
constructor(email: string) { | |
this.value = email; | |
} | |
getEmail() { | |
return this.value; | |
} | |
} | |
class ValidEmail extends BaseEmail { | |
getValidEmail() { | |
return this.getEmail(); | |
} | |
} | |
class InvalidEmail extends BaseEmail { | |
getInvalidEmail() { | |
return this.getEmail(); | |
} | |
} | |
class AnotherEmail extends BaseEmail { | |
getAnotherEmail() { | |
return this.getEmail(); | |
} | |
} | |
const createEmail = (inputEmail: string): BaseEmail => { | |
if (inputEmail.includes('@')) { | |
return new ValidEmail(inputEmail); | |
} | |
return new InvalidEmail(inputEmail); | |
}; | |
const handleValidEmail = (email: ValidEmail) => { | |
return `valid email ${email.getValidEmail()}`; | |
}; | |
const handleInvalidEmail = (email: InvalidEmail) => { | |
return `invalid email ${email.getInvalidEmail()}`; | |
}; | |
const email0 = createEmail('abc'); | |
const email1 = createEmail('abc@example'); | |
const email2 = new AnotherEmail('another@example'); | |
const result0 = match(email0) | |
.case(ValidEmail, handleValidEmail) | |
.case(InvalidEmail, handleInvalidEmail) | |
.default(() => 'default 0'); | |
const result1 = match(email1) | |
.case(ValidEmail, handleValidEmail) | |
.case(InvalidEmail, handleInvalidEmail) | |
.default(() => 'default 1'); | |
const result2 = match(email2) | |
.case(ValidEmail, handleValidEmail) | |
.case(InvalidEmail, handleInvalidEmail) | |
.default(() => 'default 2'); | |
console.log({ | |
result0, | |
result1, | |
result2, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment