Skip to content

Commit bde20cf

Browse files
authored
fix(frontend) :: typecheck Bootstrap and Tom Select calls
Now that we import 3rd party browser libraries, we can also import their types.
1 parent 03c6c4b commit bde20cf

3 files changed

Lines changed: 17 additions & 22 deletions

File tree

‎frontend/src/globals.d.ts‎

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,9 @@ type Untyped = any;
1111
/** Leaflet, loaded from a CDN by sqlpage_map when a page holds a map. */
1212
declare const L: Untyped;
1313

14-
/**
15-
* A Bootstrap a page loaded for itself, preferred over the bundled copy. Its
16-
* widgets are untyped: naming a few of them here would only claim more than
17-
* this file knows.
18-
*/
19-
interface PageBootstrap {
20-
[widget: string]: Untyped;
21-
}
22-
2314
interface Window {
2415
/** Every chart rendered on the page, in the order they were built. */
2516
charts?: unknown[];
26-
bootstrap?: PageBootstrap;
17+
/** A Bootstrap a page loaded for itself, preferred over the bundled copy. */
18+
bootstrap?: typeof import("@tabler/core").bootstrap;
2719
}

‎frontend/src/sqlpage.js‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ import { add_init_fn } from "./init.js";
44
// A page may load its own Bootstrap; prefer it over the bundled copy.
55
const page_bootstrap = () => window.bootstrap ?? bundled_bootstrap;
66

7+
/**
8+
* Bootstrap declares getOrCreateInstance on the base class, which returns a
9+
* BaseComponent and so loses show().
10+
* @typedef {InstanceType<typeof bundled_bootstrap.Toast>} ToastWidget
11+
* @typedef {InstanceType<typeof bundled_bootstrap.Modal>} ModalWidget
12+
*/
13+
714
const nonce = /** @type {HTMLScriptElement} */ (document.currentScript).nonce;
815

916
function sqlpage_card() {
@@ -368,7 +375,7 @@ function open_toasts_for_hash(toasts) {
368375
if (!hash) return;
369376
for (const toast of toasts) {
370377
if (normalize_hash(toast.dataset.toastTrigger) === hash) {
371-
Toast.getOrCreateInstance(toast).show();
378+
/** @type {ToastWidget} */ (Toast.getOrCreateInstance(toast)).show();
372379
}
373380
}
374381
}
@@ -413,7 +420,9 @@ function sqlpage_toast() {
413420
}
414421

415422
toast.removeAttribute("data-pre-init");
416-
const instance = Toast.getOrCreateInstance(toast);
423+
const instance = /** @type {ToastWidget} */ (
424+
Toast.getOrCreateInstance(toast)
425+
);
417426
initialized_toasts.push(toast);
418427
toast.addEventListener("hidden.bs.toast", () => {
419428
restore_focus_after_toast(toast, container);
@@ -488,7 +497,9 @@ function open_modal_for_hash() {
488497
if (!hash) return;
489498
const modal = document.getElementById(hash);
490499
if (!modal?.classList.contains("modal")) return;
491-
const bootstrap_modal = page_bootstrap().Modal.getOrCreateInstance(modal);
500+
const bootstrap_modal = /** @type {ModalWidget} */ (
501+
page_bootstrap().Modal.getOrCreateInstance(modal)
502+
);
492503
bootstrap_modal.show();
493504
modal.addEventListener(
494505
"hidden.bs.modal",

‎tests/end-to-end/globals.d.ts‎

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
11
// What the browser tests reach for on the page: widgets that the scripts under
22
// test attach to elements at runtime.
33

4-
interface TomSelectInstance {
5-
getValue(): string | string[];
6-
setTextboxValue(value: string): void;
7-
focus(): void;
8-
open(): void;
9-
options: Record<string, { label?: string } | undefined>;
10-
}
11-
124
interface HTMLElement {
135
/** Attached by sqlpage_select_dropdown to every select it takes over. */
14-
tomselect?: TomSelectInstance;
6+
tomselect?: import("tom-select/popular").default;
157
}

0 commit comments

Comments
 (0)