FastjsModuleBase
Every "instance" produced by Fastjs (FastjsDom, FastjsDomList, FastjsDate, FastjsRequest, FastjsCookie) is built by the same internal factory, so they all inherit a common surface called FastjsModuleBase.
It gives you:
- Custom props – attach business data directly on the instance.
- Custom events – attach named methods that receive the instance as their first argument.
then– run a callback later (setTimeout-style) while keeping the chain.
FastjsRequestis the only exception: it does not inheritthenbecause.thenon requests is overloaded to register success callbacks.
Type Declaration
interface FastjsModuleBase {
[key: string]: any;
setCustomProp(name: string, value: any): this;
setCustomProps(props: { [key: string]: any }): this;
getCustomProp(name: string): any;
setCustomEvent(
name: string,
func: (module: this, ...args: any[]) => void,
setup?: boolean,
): this;
callCustomEvent(name: string, ...args: any[]): this;
then(func: (e: this) => void, time?: number): this;
}Custom props
setCustomProp(name, value) / setCustomProps(props)
Attach arbitrary keys onto the instance.
import { dom } from "jsfast";
const card = dom
.newEl("div")
.setCustomProp("itemId", 42)
.setCustomProps({ rowId: 1, draft: true });
card.itemId; // 42 (direct read works)
card.getCustomProp("itemId"); // 42 (semantic helper)Reserved keys
Don't overwrite Fastjs internals such as _el, _list, _events, _date, construct, data, config, … Use names that won't collide with the instance's own API.
getCustomProp(name)
Read a key set via the helpers above. Equivalent to instance[name]; the helper is mostly there for readability.
Custom events
setCustomEvent(name, func, setup = false)
Attach a named method to the instance. The first argument of func is the instance itself, so you can keep chaining inside the body.
import { date } from "jsfast";
const greeter = date.create();
greeter.setCustomEvent("hello", (self, who) => {
console.log(`hello ${who} @ ${self.toString()}`);
});
greeter.hello("Alice");setup = true calls the function once during registration, useful for initialisation:
greeter.setCustomEvent("autoinit", (self) => self.refresh(), true);callCustomEvent(name, ...args)
Trigger a registered event explicitly. Equivalent to instance[name](...), but returns the instance so it composes with other chain methods:
greeter.callCustomEvent("hello", "Bob").callCustomEvent("hello", "Carol");Delay with then(func, time = 0)
Run func(this), optionally after time milliseconds. The method always returns the instance so the chain continues immediately.
dom("#tip")
.addClass("show")
.then((el) => el.removeClass("show"), 1500); // hide after 1.5stime = 0→ call synchronously (nosetTimeoutqueued).time > 0→ equivalent tosetTimeout(() => func(this), time).- Development mode warns when
funcis not a function ortimeis not a number.
Worked example: toast component
import { dom } from "jsfast";
function makeToast(text: string, duration = 2000) {
return dom
.newEl("div", {
text,
class: ["toast"],
css: {
position: "fixed",
bottom: "32px",
left: "50%",
transform: "translateX(-50%)",
padding: "8px 16px",
borderRadius: "8px",
background: "#222",
color: "white",
opacity: "0",
transition: "opacity .2s",
},
})
.setCustomEvent(
"show",
(self) => {
self.push(document.body);
self.then((el) => el.setStyle({ opacity: "1" }), 0);
self.then((el) => {
el.setStyle({ opacity: "0" });
el.then((e) => e.remove(), 300);
}, duration);
},
true,
); // setup=true: trigger immediately
}
makeToast("Saved", 1500);Extending instances with TypeScript
Because FastjsModuleBase is declared as { [key: string]: any }, TypeScript will let you assign any property. You can opt into stricter types via declaration merging inside your own project:
declare module "jsfast" {
interface FastjsDomAtom<E> {
rowId?: number;
draft?: boolean;
}
}
dom.newEl("div").setCustomProp("rowId", 1).rowId; // typed as number | undefinedThe
*Atominterfaces are internal types; they're stable enough for declaration merging but please pin a version range if you depend on this in a library.