Bitf
A tiny and robust library to manage bitflags / bitsets / optionsets in TypeScript & JavaScript
Install / Use
/learn @neg4n/BitfREADME
bitf
bitf is a tiny and fast bit flags (other terms: bit fields, optionsets) management library for TypeScript/JavaScript
What are bitflags?
Bitflags are a way to represent a set of boolean options using a single integer. Each bit in the number corresponds to a different option, allowing for efficient storage and manipulation of multiple flags at once. Concept of creating this library originates from the article "Everything About Bitflags".
Features
- Type safety via Tagged types.
- Lightweight and fast, almost native bitwise performance with minimal abstraction layer.
- No runtime dependencies.
- Robust and ready-to-use on production.
- Comprehensive tests suite with 100% test coverage.
.describe()iterator for better debugging and visualization of the bit flags.- Range guards while defining bit flags.
Installation
npm i bitf
# or
yarn add bitf
# or
pnpm add bitf
# or
bun add bitf
Usage Example
This example shows a pizza ordering system where customers can customize their toppings. The restaurant starts with a default Pepperoni pizza and enforces three business rules:
- cheese must always be included (it's the base of toppings every pizza being sold)
- only one meat type is allowed per pizza (to ensure good taste combinations)
- customers get an automatic discount when they order a Hawaiian pizza (cheese + ham + pineapple)
The code uses bitflags to efficiently track which toppings are selected and validate these rules, demonstrating how bitflags can handle complex combinations while enforcing business logic and detecting special cases for promotions without hundreds of lines of code of copying, modyfing and iterating over Objects and Arrays of Objects and mapping boolean states and wasting the network bandwidth.
import { type Bitflag, bitflag, defineBitflags } from "bitf";
// This should probably live in a file shared between frontend/backend contexts
const Toppings = defineBitflags({
CHEESE: 1 << 0,
PEPPERONI: 1 << 1,
MUSHROOMS: 1 << 2,
OREGANO: 1 << 3,
PINEAPPLE: 1 << 4,
BACON: 1 << 5,
HAM: 1 << 6,
});
// Can be mapped on frontend using InferBitflagsDefinitions<typeof Toppings> and .describe() function
type PizzaOrderPreferences = Readonly<{
desiredSize: "small" | "medium" | "large";
toppingsToAdd: Bitflag;
toppingsToRemove: Bitflag;
}>;
export async function configurePizzaOrder({
desiredSize,
toppingsToAdd,
toppingsToRemove,
}: PizzaOrderPreferences) {
if (bitflag(toppingsToRemove).has(Toppings.CHEESE))
throw new Error("Cheese is always included in our pizzas!");
const defaultPizza = bitflag().add(Toppings.CHEESE, Toppings.PEPPERONI);
const pizzaAfterRemoval = processToppingsRemoval(
defaultPizza,
toppingsToRemove
);
validateMeatAddition(pizzaAfterRemoval, toppingsToAdd);
// ... some additional logic like checking the toppings availability in the restaurant inventory
// ... some additional logging using the .describe() function for comprehensive info
const finalPizza = bitflag(pizzaAfterRemoval).add(toppingsToAdd);
return {
size: desiredSize,
pizza: finalPizza,
metadata: {
hawaiianPizzaDiscount: bitflag(finalPizza).hasExact(
Toppings.CHEESE,
Toppings.HAM,
Toppings.PINEAPPLE
),
},
};
}
function processToppingsRemoval(
currentPizza: Bitflag,
toppingsToRemove: Bitflag
) {
if (toppingsToRemove) return bitflag(currentPizza).remove(toppingsToRemove);
return currentPizza;
}
function validateMeatAddition(currentPizza: Bitflag, toppingsToAdd: Bitflag) {
const currentHasMeat = bitflag(currentPizza).hasAny(
Toppings.PEPPERONI,
Toppings.BACON,
Toppings.HAM
);
const requestingMeat = bitflag(toppingsToAdd).hasAny(
Toppings.PEPPERONI,
Toppings.BACON,
Toppings.HAM
);
if (currentHasMeat && requestingMeat)
throw new Error("Only one type of meat is allowed per pizza!");
}
Top-level API
bitf library exposes the following:
Core runtime functionality:
bitflag- the main function to perform bitwise operations on the flags.- Bitwise operations abstraction
- Debugging and visualization
describe- returns an iterator for describing the flags
- Interoperability between the library and other code
defineBitflags- utility to define type-safe set of bit flags
[!NOTE] All of the operations support passing multiple flags at once through variadic arguments.
Utility functions
makeBitflag- utility to create aBitflagTagged Type from a number if it is possible.isBitflag- utility to check if number is within allowed range and to create aBitflagTagged type out of itunwrapBitflag- utility to unwrap the Tagged type ofBitflagto be justnumber
Type utilities
Bitflag- The tagged type for individual bitflag numbersBitflagsDefinitions<T>- The type for frozen bitflag definition objects returned bydefineBitflagsInferBitflagsDefinitions<T>- Type utility to extract the shape from bitflag definitions (similar to Zod'sz.infer)
API Reference
bitflag(Bitflag | number)
Bitflag is a factory function that returns object with a specific set of operations for managing the flags. It accepts any number or Bitflag Tagged Type as an argument and then allows you to perform various operations on it. It also supports methods like toString(), value getter and valueOf() for compatibility with other JavaScript APIs.
Important: The bitflag function's returned object's methods are non-chainable - each call to the bitwise operations returns just a number wrapped with the Bitflag Tagged Type. It does not return a new instance of the bitflag object.
Correct Usage
const combinedFlags = bitflag(flags.NONE).add(
flags.MY_OTHER_FLAG,
flags.ANOTHER_FLAG
);
if (bitflag(combinedFlags).has(flags.ANOTHER_FLAG)) {
console.log("has ANOTHER_FLAG");
}
Incorrect Usage
// ❌ This will not work as expected
if (
bitflag(flags.NONE)
.add(flags.MY_OTHER_FLAG, flags.ANOTHER_FLAG)
.has(flags.ANOTHER_FLAG)
) {
console.log("has ANOTHER_FLAG");
}
Bitwise Operations
.has(...Bitflag[])
Checks if all the specified flags are set in the current set. Returns true if all flags are present, false otherwise.
Tip: Passing no arguments to .has() always returns false.
Examples
bitflag(flags.READ | flags.WRITE).has(flags.READ); // single defined
bitflag(flags.READ | flags.WRITE | flags.EXECUTE).has(
flags.READ,
flags.WRITE
); // multiple defined
bitflag(flags.READ | flags.WRITE).has(flags.READ, makeBitflag(1 << 1)); // mixed
.hasAny(...Bitflag[])
Checks if any of the specified flags are set in the current set. Returns true if at least one flag is present, false if none are present.
Tip: Passing no arguments to .hasAny() always returns false.
Examples
bitflag(flags.READ | flags.WRITE).hasAny(flags.EXECUTE); // single defined
bitflag(flags.READ).hasAny(flags.EXECUTE, flags.DELETE); // multiple defined
bitflag(flags.READ).hasAny(flags.EXECUTE, makeBitflag(1 << 0)); // mixed
.hasExact(...Bitflag[])
Checks if the current set matches exactly the specified flags - no more, no less. Returns true if the flags match exactly, false otherwise.
Tip: Calling .hasExact() with no arguments checks if the current value is exactly zero.
Examples
bitflag(flags.READ | flags.WRITE).hasExact(flags.READ, flags.WRITE); // single defined exact match
bitflag(flags.NONE).hasExact(); // multiple defined (empty means zero flags)
bitflag(flags.READ).hasExact(makeBitflag(1 << 0)); // mixed
.add(...Bitflag[])
Adds the specified flags to the current set. Returns a new number wrapped in Bitflag<T> as the updated flags.
Tip: Adding the same flag multiple times is idempotent - it won't change the result.
Examples
bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG); // single defined
bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG, flags.ANOTHER_FLAG); // multiple defined
bitflag(flags.MY_FLAG).add(flags.MY_OTHER_FLAG, makeBitflag(1 << 2)); // mixed
.remove(...Bitflag[])
Removes the specified flags from the current set. Returns a new number wrapped in Bitflag<T> as the updated flags.
Tip: Removing non-existent flags has no effect and won't change the result.
Examples
bitflag(flags.READ | flags.WRITE).remove(flags.WRITE); // single defined
bitflag(flags.ALL).remove(flags.WRITE, flags.DELETE); // multiple defined
bitflag(flags.READ | flags.WRITE).remove(flags.WRITE, makeBitflag(1 << 3)); // mixed
.toggle(...Bitflag[])
Toggles the specified flags in the current set - adds them if not present, removes them if present. Returns a new number wrapped in Bitflag<T> as the updated flags.
Examples
bitflag(flags.READ).toggle(flags.WRITE); // single defin
Related Skills
node-connect
343.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
90.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Writing Hookify Rules
90.0kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
review-duplication
99.7kUse this skill during code reviews to proactively investigate the codebase for duplicated functionality, reinvented wheels, or failure to reuse existing project best practices and shared utilities.
