- Strongly-typed collection with a configurable primary key
- Lifecycle hooks (
insert,patch,remove,clear) with before/after stages - Event-driven updates via
onUpdatecallback andaddEventListener - Full support for
string,number, andbigintprimary keys - Zero runtime dependencies
npm install @webeach/collectionpnpm add @webeach/collectionyarn add @webeach/collectionNo build step needed — load directly in the browser via unpkg:
<scripttype="module">import{Collection}from'https://unpkg.com/@webeach/collection';constusers=newCollection({primaryKey: 'id'});users.appendItem({id: 1,name: 'Alice'});</script>import{Collection}from'@webeach/collection';constusers=newCollection({primaryKey: 'id',});users.appendItem({id: 1,firstName: 'Ivan',lastName: 'Petrov'});users.appendItem({id: 2,firstName: 'Jason',lastName: 'Statham'});console.log(users.numItems);// 2console.log(users.getItem(2)?.firstName);// 'Jason'import{Collection}from'@webeach/collection';constproducts=newCollection({primaryKey: 'sku'});products.appendItem({sku: 'A001',name: 'Laptop'});products.replaceItem('A001',{sku: 'A001',name: 'Laptop Pro'});console.log(products.getItem('A001')?.name);// 'Laptop Pro'import{Collection}from'@webeach/collection';consttasks=newCollection({primaryKey: 'id',initialItems: [{id: 1,title: 'Task 1'},{id: 2,title: 'Task 2'},],});tasks.setItems([{id: 3,title: 'New Task 3'},{id: 4,title: 'New Task 4'},]);console.log(tasks.numItems);// 2console.log(tasks.getItem(3)?.title);// 'New Task 3'import{Collection}from'@webeach/collection';constlist=newCollection({primaryKey: 'id'});list.onUpdate=(event)=>{console.log('Items updated:',event.detail);};// Or via addEventListenerlist.addEventListener('update',(event)=>{console.log('Items updated:',event.detail);});list.appendItem({id: 1,name: 'Alice'});import{Collection,$CollectionHookDispatcherSymbol,}from'@webeach/collection';constusers=newCollection({primaryKey: 'id'});// Block insertion of items with even idsconst{ unregister }=users[$CollectionHookDispatcherSymbol].register('insert:before',({ item })=>{if(item.id%2===0){returnfalse;// cancel insertion}},);users.appendItem({id: 1,name: 'Alice'});// succeedsusers.appendItem({id: 2,name: 'Bob'});// blockedconsole.log(users.numItems);// 1unregister();- constructor
- Methods
- Properties
- Hooks
- constructor
- Inherits CustomEvent API
The collection is fully generic and infers types based on the primary key and item shape.
import{Collection}from'@webeach/collection';interfaceUser{id: number;name: string;role: 'admin'|'user';}constusers=newCollection<'id',number,User>({primaryKey: 'id',});users.appendItem({id: 1,name: 'Alice',role: 'admin'});constuser=users.getItem(1);// user: CollectionItem<'id', number, User> | nullimport{FC,useEffect,useRef,useState}from'react';import{Collection}from'@webeach/collection';interfaceTask{id: number;title: string;done: boolean;}exportconstTaskList: FC=()=>{constcollectionRef=useRef(newCollection<'id',number,Task>({primaryKey: 'id'}),);const[tasks,setTasks]=useState<Task[]>([]);useEffect(()=>{constcollection=collectionRef.current;collection.onUpdate=(event)=>{setTasks([...event.detail]asTask[]);};collection.appendItem({id: 1,title: 'Buy groceries',done: false});collection.appendItem({id: 2,title: 'Write tests',done: false});},[]);consttoggle=(id: number)=>{constitem=collectionRef.current.getItem(id);if(item){collectionRef.current.patchItem(id,{done: !item.done});}};return(<ul>{tasks.map((task)=>(<likey={task.id}onClick={()=>toggle(task.id)}>{task.done ? '✓' : '○'}{task.title}</li>))}</ul>);};import{Collection,$CollectionHookDispatcherSymbol,}from'@webeach/collection';functioncreateBoundedCollection<Textends{id: number}>(maxSize: number){constcollection=newCollection<'id',number,T>({primaryKey: 'id'});collection[$CollectionHookDispatcherSymbol].register('insert:before',()=>{if(collection.numItems>=maxSize){returnfalse;}});returncollection;}constlimited=createBoundedCollection(3);limited.appendItem({id: 1});// oklimited.appendItem({id: 2});// oklimited.appendItem({id: 3});// oklimited.appendItem({id: 4});// blocked — limit reachedconsole.log(limited.numItems);// 3Development and support: Ruslan Martynov
If you have suggestions or found a bug, feel free to open an issue or submit a pull request.
This package is distributed under the MIT License.