Created
June 23, 2023 12:14
-
-
Save Herve07h22/acda50482d5c1d40ee1bf4b204be575e to your computer and use it in GitHub Desktop.
Pattern matching instead of Visitor pattern
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
import { match, P } from "ts-pattern"; | |
const headerBlocType = { | |
Header: "header", | |
Paragraph: "paragraph", | |
Image: "image", | |
} as const; | |
interface HeadBlockData { | |
text: string; | |
level: 1 | 2 | 3 | 4 | 5 | 6; | |
} | |
interface ParagraphBlockData { | |
text: string; | |
} | |
interface ImageBlockData { | |
url: string; | |
caption: string; | |
} | |
export class HeaderBlock { | |
type = headerBlocType.Header; | |
constructor(public data: HeadBlockData) {} | |
} | |
export class ParagraphBlock { | |
type = headerBlocType.Paragraph; | |
constructor(public data: ParagraphBlockData) {} | |
} | |
export class ImageBlock { | |
type = headerBlocType.Image; | |
constructor(public data: ImageBlockData) {} | |
} | |
// Type union instead of inheritance ! | |
export type Block = HeaderBlock | ParagraphBlock | ImageBlock; | |
export class BlockEditor { | |
blocks: Array<Block> = []; | |
addBlock(block: Block) { | |
this.blocks.push(block); | |
} | |
removeBlock(block: Block) { | |
const index = this.blocks.indexOf(block); | |
index !== -1 && this.blocks.splice(index, 1); | |
} | |
outputHtml() { | |
return this.blocks.reduce((html, block) => html + renderToHtml(block), ""); | |
} | |
} | |
// This is where the pattern matching shines | |
function renderToHtml(block: Block) { | |
return match(block) | |
.with( | |
{ type: "header", data: P.select() }, | |
({ level, text }) => `<h${level}>${text}</h${level}>` | |
) | |
.with( | |
{ type: "paragraph", data: P.select() }, | |
({ text }) => `<p>${text}</p>` | |
) | |
.with( | |
{ type: "image", data: P.select() }, | |
({ url, caption }) => `<img src="${url}" alt="${caption}" />` | |
) | |
.exhaustive(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment