Skip to content

Instantly share code, notes, and snippets.

@simonbuchan
Created May 18, 2017 01:02
Show Gist options
  • Save simonbuchan/2f732e9c64aa6249cabb0e95540cf4f0 to your computer and use it in GitHub Desktop.
Save simonbuchan/2f732e9c64aa6249cabb0e95540cf4f0 to your computer and use it in GitHub Desktop.
Using type guards with bitmasks
const TYPE_MASK = 0xFFFF;
const TEXT_TYPE = 1;
const IMAGE_TYPE = 2;
const IS_SIZED = 1 << 16;
const IS_COLORED = 1 << 17;
const HAS_CHILDREN = 1 << 18;
interface IDrawable {
tag: number;
}
function drawableType({ tag }: IDrawable) {
return tag & TYPE_MASK;
}
// Types
interface Text extends IDrawable {
text: string;
}
function isText(drawable: IDrawable): drawable is Text {
return drawableType(drawable) === TEXT_TYPE;
}
interface Image extends IDrawable {
url: string;
}
function isImage(drawable: IDrawable): drawable is Image {
return drawableType(drawable) === IMAGE_TYPE;
}
// Features
interface Sized {
width: number;
height: number;
}
function isSized(drawable: IDrawable): drawable is Sized {
return 0 !== (tag & IS_SIZED);
}
interface Colored {
red: number;
green: number;
blue: number;
}
function isColored(drawable: IDrawable): drawable is Colored {
return 0 !== (drawable.tag & IS_SIZED);
}
interface Parent {
children:
}
draw(drawable: IDrawable, target: IDrawTarget, state: DrawState = new DrawState()) {
state = state.clone();
if (isSized(drawable)) {
state.setSize(drawable.width, drawable.height);
}
if (isColored(drawable) {
state.color(drawable.red, drawable.green, drawable.blue);
}
if (isText(drawable)) {
target.drawText(drawable.text, state);
} else if (isImage(drawable)) {
target.drawImage(drawable.url, state);
} else {
throw new Error(`Unhandled drawable typecode: ${drawableType(drawable)}`);
}
if (hasChildren(drawable)) {
for (const child of drawable.children) {
draw(child, target, state);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment