# DOCUMENTS-API-Typen nutzen

Die wichtigsten Objekte sind ohne eigenes Zutun typisiert: `context`, `util` und alle API-Klassen wie `DocFile`, `FileResultset`, `SystemUser` oder `Register` kommen aus `portalScripting.d.ts`. Den größten Nutzen bringen aber unsere eigenen Mappentypen aus `fileTypes.d.ts`.

### Mappentypen: Felder werden geprüft

Für jeden Mappentyp erzeugt die Extension einen eigenen Typ (z.B. `dexRecord`, `dexRecordCategory`, `RIBProject`). Er kennt alle Felder, Register und Referenzfelder. Die API-Methoden sind so typisiert, dass VS Code den richtigen Mappentyp selbst erkennt:

```javascript
const rec = context.createFile("dexRecord");   // Typ: dexRecord
rec.Subject = "Rechnung 4711";                  // OK, Feld existiert
rec.Subjekt = "Rechnung 4711";                  // Fehler: Property 'Subjekt' does not exist on type 'dexRecord'
rec.getRegisterByName("Attachments");           // Registername wird geprüft

for (const cat of new FileResultset("dexRecordCategory", "", "")) {
    cat.CategoryName;                           // Typ: dexRecordCategory
}
```

Ein zusätzliches `/** @type {dexRecord} */` vor `context.createFile("dexRecord")` ist deshalb unnötig.

### context.file eingrenzen

`context.file` ist nur als allgemeines `DocFile` bekannt, denn das Skript kann an jeder Mappe hängen. Wer weiß, welcher Mappentyp ankommt, grenzt ihn per Cast ein. Aus `Gadget_DexDocumentTreeNavigator.js`:

```javascript
switch(fileTypeForFilter) {
    case "dexRecordConfiguration":
        const dexRecConf = /** @type {DocFile & dexRecordConfiguration} */ (file);
        filterValue = dexRecConf?.UniqueID || "";
        break;
    case "dexRecordCategory":
        const dexRecCat = /** @type {DocFile & dexRecordCategory} */ (file);
```

Referenzfelder liefern ebenfalls typisierte Mappen. Weil eine Referenz leer sein kann, gehört `null` mit in den Typ (`DexRecordReference.mjs`):

```javascript
/** @type {null | DocFile & dexRecordConfiguration} */ (this.dossierFile.getReferenceFile("DexRecordConfiguration"))
```

Auch Feldnamen in Variablen lassen sich einschränken: `/** @type {keyof dexRecordFields} */ (key)`.

### Gadgets und Client-Code

Die Gadget-API bringt eigene Typen mit (`gadgetApi.d.ts`, `documentsClientSdk.d.ts`). Aus `Gadget_DEXPRO_ShowDBData.js`:

```javascript
/**
 * @param {GadgetContext} gadgetContext
 * @param {otris} otris
 * @returns {otris.gadget.gui.Form}
 */
function showDBData(gadgetContext, otris) {
    ...
    /** @type {ContainerButtonConfig} */
    let showDataButtonConfig = {
        "id": "showDataButtonId",
        ...
    }
```

Variablen, die erst im Browser existieren, deklariert man nur für die Typprüfung (`Gadget_DEXPRO_MailQueue.js`):

```javascript
/**
 * Nur zur Typpruefung: In den clientseitigen Funktionen (clientScript,
 * addClientFunction, addOnGadgetLoad) stellt der Client diese Variable bereit.
 * Serverseitig wird sie nie gelesen.
 *
 * @type {documents.sdk.DocumentsContext}
 */
var documentsContext;
```

### Skript-Parameter

Parameter eines Portalskripts stellt der Server als globale Variablen bereit. Die Typings kennen sie nicht. Das saubere Muster: zur Laufzeit prüfen, casten und den Grund dokumentieren (`Gadget_DexRecordCategory_FiletypeFilter.js`):

```javascript
/**
 * `query` is injected as a global variable by the script engine and is not part of the typings.
 */
// @ts-ignore
const autoCompleteQuery = /** @type {string} */ (typeof query === "string" ? query : "");
```