Eigene Typen definieren
Sobald ein Objekt an mehreren Stellen vorkommt (Konfigurationen, Rückgabewerte, JSON von externen Schnittstellen), bekommt es einen eigenen Typ mit @typedef. Der Name ist danach in der ganzen Datei nutzbar.
Objekt-Strukturen: @typedef und @property
Aus Gadget_DexRecordCategory_FiletypeFilter.js. Jede Eigenschaft hat Typ, Name und eine kurze Erklärung:
/**
* One selectable filter property of the grid.
* @typedef {object} FilterProperty
* @property {string} propertyKey technical key stored in `FileTypeFilterData`
* @property {string} label label shown in the key column
* @property {string} editorType property grid editor, `SELECT` or `TEXT`
* @property {string} searchText lower cased text the autocomplete matches against
*/
Das vollständigste Beispiel im Code steht in DEXPRO__ExtDataProfiles.js. Es zeigt optionale Eigenschaften, Funktionen als Eigenschaft, Dictionaries und verschachtelte Typen:
/**
* @typedef {Object} ExtDataProfile
* @property {string} id unique id, "<source>.<entity>" (matched case-insensitively)
* @property {string} [title] multilingual heading of the gadget
* @property {(data: Object, record: any) => boolean} [match] auto-detection, called with the first data object
* @property {string[]} [cardTitle] JSON keys, the first non-empty value is the card heading
* @property {Object<string, string>} [labels] key / base name / path -> multilingual label
* @property {ExtDataGroup[]} [groups] sections of the card, unlisted rows go to "Weitere Angaben"
* @property {Array<string|RegExp>} [include] allowlist for top-level rows (empty = everything)
*/
Bestehende Typen erweitern
Mit & wird ein Typ um Felder ergänzt, ohne ihn zu kopieren. Aus Gadget_DEXPRO_Contract_Certs_MailNotifications.js:
/**
* A MailConfig while being edited in the form, carrying the transient
* "Auswählen" checkbox state (stripped before persisting).
*
* @typedef {MailConfig & { __selected?: boolean }} MailConfigDraft
*/
Konstanten als Enum: @enum und @readonly
Aus DexDossier_OnFileView.js. @readonly verhindert versehentliches Überschreiben, @enum {string} macht den Objektnamen als Typ nutzbar (@param {NOTIFICATION_TYPE} type):
/**
* Notification types accepted by {@link notifyUser}.
* @readonly
* @enum {string}
*/
const NOTIFICATION_TYPE = {
INFO: "info",
WARNING: "warning",
ERROR: "error",
SUCCESS: "success",
DEBUG: "debug"
};
Typen über Dateigrenzen teilen
Ein Typ wird einmal in der Bibliothek definiert und überall per import() wiederverwendet. MailInfo steht in DEXPRO__MailQueueLib.js und wird in Gadget_DEXPRO_MailQueue.js so eingebunden:
/** @typedef {import("../Dexpro_Lib.cat/DEXPRO__MailQueueLib").MailInfo} MailInfo */
Das klappt nur bei relativen Pfaden (./ oder ../). Bei Skriptnamen ohne Pfad (z.B. import("DexRecordReference")) findet VS Code die Datei in der Regel nicht.
Für Fortgeschrittene
- Typ aus einer Funktion ableiten:
@property {ReturnType<typeof findExtDataProfile>} profile(Gadget_DEXPRO_showExtData.js). Der Typ ändert sich automatisch mit, wenn sich die Funktion ändert. - Generics mit @template: In
DEXPRO_Gadget_FormLib.jsliefertgetFormElementsein Objekt mit genau den Schlüsseln des übergebenen Schemas:
/**
* Gets fields of the form based on the provided schema.
* @this {otris.gadget.gui.Form}
* @template {FieldSchema} T
* @param {T} fieldSchema
* @returns {Record<keyof T, otris.gadget.gui.Element>}
*/
_FormPrototype.getFormElements = function(fieldSchema) {