Custom Structures & Types
Override built-in structures and use inferred structure types.
Hoshimi allows you to replace default classes with custom implementations. This guide covers both overriding structures and using their inferred types.
Basic Override Pattern
Create a custom subclass and assign it to the Structures factory.
import { , } from 'hoshimi';
class extends {
public (): boolean {
return this. > 120;
}
}
. = (...) => new (...);
declare module 'hoshimi' {
interface CustomizableStructures {
: ;
}
}The augmentation is what re-types everything
Assigning to Structures swaps the class at runtime; augmenting CustomizableStructures is what makes
player.filterManager, PlayerStructure and every other reference resolve to your subclass. A local
interface CustomizableStructures in your file does nothing — it has to be inside
declare module 'hoshimi'.
Multiple Overrides
Override several structures at once for comprehensive customization.
import { , , , } from 'hoshimi';
class extends {}
class extends {}
class extends {}
. = (...) => new (...);
. = (...) => new (...);
. = (...) => new (...);
declare module 'hoshimi' {
interface CustomizableStructures {
: ;
: ;
: ;
}
}Every structure is overridable: Player, Node, NodeManager, Rest, Queue, LyricsManager,
FilterManager, Track, UnresolvedTrack, PlayerVoiceState and PlayerStorageAdapter.
Using Structure Types
The *Structure type aliases represent the final instance types. Use them in function signatures for flexibility.
import type { , } from 'hoshimi';
function (: ): void {
// Works with default Player or any custom Player replacement
.(`Guild: ${.}`);
}
function (: ): string {
return ..;
}Module Augmentation for Custom Data
Extend built-in structures with custom properties via module augmentation.
import type { LyricsResult } from 'hoshimi';
declare module 'hoshimi' {
interface CustomizablePlayerStorage {
: boolean;
: boolean;
: string;
: LyricsResult;
}
interface CustomizableTrack {
: {
: string;
: string;
};
}
}Best Practices
- Override structures once during bootstrap (before creating any managers).
- Keep constructor signatures unchanged to maintain compatibility.
- Add narrow, domain-specific methods instead of rewriting core flow logic.
- Use
*Structuretypes in function signatures to avoid coupling to concrete classes. - Keep extensions strongly typed after overrides with
InferCustomStructure.