@@ -290,19 +290,52 @@ export class World {
290290 * @overload set<T>(entityId: EntityId, componentType: EntityId<T>, component: NoInfer<T>): void
291291 * Adds or updates a component with data on the entity
292292 *
293+ * @overload set<T>(componentId: ComponentId<T>, component: NoInfer<T>): void
294+ * Adds or updates a singleton component (shorthand for set(componentId, componentId, component))
295+ *
293296 * @throws {Error } If the entity does not exist
294297 * @throws {Error } If the component type is invalid or is a wildcard relation
295298 *
296299 * @example
297300 * world.set(entity, Position, { x: 10, y: 20 });
298301 * world.set(entity, Marker); // void component
302+ * world.set(GlobalConfig, { debug: true }); // singleton component
299303 * world.sync(); // Apply changes
300304 */
301305 set ( entityId : EntityId , componentType : EntityId < void > ) : void ;
302306 set < T > ( entityId : EntityId , componentType : EntityId < T > , component : NoInfer < T > ) : void ;
303- set ( entityId : EntityId , componentType : EntityId , component ?: any ) : void {
304- if ( ! this . exists ( entityId ) ) {
305- throw new Error ( `Entity ${ entityId } does not exist` ) ;
307+ set < T > ( componentId : ComponentId < T > , component : NoInfer < T > ) : void ;
308+ set ( entityId : EntityId | ComponentId , componentTypeOrComponent ?: EntityId | any , maybeComponent ?: any ) : void {
309+ // Handle singleton component overload: set(componentId, data)
310+ if ( maybeComponent === undefined && componentTypeOrComponent !== undefined ) {
311+ const detailedType = getDetailedIdType ( entityId ) ;
312+ // Check if this looks like a singleton call (2 arguments, second is not an EntityId)
313+ if ( detailedType . type === "component" || detailedType . type === "component-relation" ) {
314+ // Singleton component: set(componentId, data)
315+ const componentId = entityId as ComponentId ;
316+ const component = componentTypeOrComponent ;
317+ if ( ! this . exists ( componentId ) ) {
318+ throw new Error ( `Component entity ${ componentId } does not exist` ) ;
319+ }
320+ const detailedComponentType = getDetailedIdType ( componentId ) ;
321+ if ( detailedComponentType . type === "invalid" ) {
322+ throw new Error ( `Invalid component type: ${ componentId } ` ) ;
323+ }
324+ if ( detailedComponentType . type === "wildcard-relation" ) {
325+ throw new Error ( `Cannot directly add wildcard relation components: ${ componentId } ` ) ;
326+ }
327+ this . commandBuffer . set ( componentId , componentId , component ) ;
328+ return ;
329+ }
330+ }
331+
332+ // Standard overload: set(entityId, componentType, data?) or set(entityId, componentType)
333+ const entityIdArg = entityId as EntityId ;
334+ const componentType = componentTypeOrComponent as EntityId ;
335+ const component = maybeComponent ;
336+
337+ if ( ! this . exists ( entityIdArg ) ) {
338+ throw new Error ( `Entity ${ entityIdArg } does not exist` ) ;
306339 }
307340
308341 const detailedType = getDetailedIdType ( componentType ) ;
@@ -313,14 +346,20 @@ export class World {
313346 throw new Error ( `Cannot directly add wildcard relation components: ${ componentType } ` ) ;
314347 }
315348
316- this . commandBuffer . set ( entityId , componentType , component ) ;
349+ this . commandBuffer . set ( entityIdArg , componentType , component ) ;
317350 }
318351
319352 /**
320353 * Removes a component from an entity.
321354 * The change is buffered and takes effect after calling `world.sync()`.
322355 * If the entity does not exist, throws an error.
323356 *
357+ * @overload remove<T>(entityId: EntityId, componentType: EntityId<T>): void
358+ * Removes a component from an entity.
359+ *
360+ * @overload remove<T>(componentId: ComponentId<T>): void
361+ * Removes a singleton component (shorthand for remove(componentId, componentId)).
362+ *
324363 * @template T - The component data type
325364 * @param entityId - The entity identifier
326365 * @param componentType - The component type to remove
@@ -330,19 +369,33 @@ export class World {
330369 *
331370 * @example
332371 * world.remove(entity, Position);
372+ * world.remove(GlobalConfig); // Remove singleton component
333373 * world.sync(); // Apply changes
334374 */
335- remove < T > ( entityId : EntityId , componentType : EntityId < T > ) : void {
336- if ( ! this . exists ( entityId ) ) {
337- throw new Error ( `Entity ${ entityId } does not exist` ) ;
375+ remove < T > ( componentId : ComponentId < T > ) : void ;
376+ remove < T > ( entityId : EntityId , componentType : EntityId < T > ) : void ;
377+ remove < T > ( entityId : EntityId | ComponentId , componentType ?: EntityId < T > ) : void {
378+ // Handle singleton component overload: remove(componentId)
379+ if ( componentType === undefined ) {
380+ const componentId = entityId as ComponentId < T > ;
381+ if ( ! this . exists ( componentId ) ) {
382+ throw new Error ( `Component entity ${ componentId } does not exist` ) ;
383+ }
384+ this . commandBuffer . remove ( componentId , componentId ) ;
385+ return ;
386+ }
387+
388+ const entityIdArg = entityId as EntityId ;
389+ if ( ! this . exists ( entityIdArg ) ) {
390+ throw new Error ( `Entity ${ entityIdArg } does not exist` ) ;
338391 }
339392
340393 const detailedType = getDetailedIdType ( componentType ) ;
341394 if ( detailedType . type === "invalid" ) {
342395 throw new Error ( `Invalid component type: ${ componentType } ` ) ;
343396 }
344397
345- this . commandBuffer . remove ( entityId , componentType ) ;
398+ this . commandBuffer . remove ( entityIdArg , componentType ) ;
346399 }
347400
348401 /**
@@ -364,6 +417,12 @@ export class World {
364417 * Checks if an entity has a specific component.
365418 * Immediately reflects the current state without waiting for `sync()`.
366419 *
420+ * @overload has<T>(entityId: EntityId, componentType: EntityId<T>): boolean
421+ * Checks if a specific component type is present on the entity.
422+ *
423+ * @overload has<T>(componentId: ComponentId<T>): boolean
424+ * Checks if a singleton component has data (shorthand for has(componentId, componentId)).
425+ *
367426 * @template T - The component data type
368427 * @param entityId - The entity identifier
369428 * @param componentType - The component type to check
@@ -373,8 +432,19 @@ export class World {
373432 * if (world.has(entity, Position)) {
374433 * const pos = world.get(entity, Position);
375434 * }
435+ * if (world.has(GlobalConfig)) {
436+ * const config = world.get(GlobalConfig);
437+ * }
376438 */
377- has < T > ( entityId : EntityId , componentType : EntityId < T > ) : boolean {
439+ has < T > ( componentId : ComponentId < T > ) : boolean ;
440+ has < T > ( entityId : EntityId , componentType : EntityId < T > ) : boolean ;
441+ has < T > ( entityId : EntityId | ComponentId , componentType ?: EntityId < T > ) : boolean {
442+ // Handle singleton component overload: has(componentId)
443+ if ( componentType === undefined ) {
444+ const componentId = entityId as ComponentId < T > ;
445+ return this . componentEntityComponents . get ( componentId ) ?. has ( componentId ) ?? false ;
446+ }
447+
378448 if ( this . isComponentEntityId ( entityId ) ) {
379449 if ( isWildcardRelationId ( componentType ) ) {
380450 const componentId = getComponentIdFromRelationId ( componentType ) ;
0 commit comments