Zum Hauptinhalt springen

Feldprojektion

fields schränkt den Rückgabetyp ein, nicht nur die Antwort. Frage nach zwei Feldern, und die Zeile, die du zurückbekommst, hat diese beiden plus id. Etwas anderes zu lesen ist ein Compile-Fehler, kein undefined zur Laufzeit:

const page = await client.v2.workspaces.projects.states.list("acme", "ENG", { fields: ["id", "name"] });
for (const state of page.data) {
console.log(state.id, state.name); // typisiert: auf dieser Zeile gibt es nur id/name
// console.log(state.color); // Kompilierfehler: `color` wurde nicht angefordert
}

Ein inline geschriebenes Array-Literal braucht kein as const. Dasselbe gilt für iterate und retrieve, und, da es dieselbe Aussage ist, für Schreibvorgänge: create, update und upsert akzeptieren fields und schränken ihre Antwort auf dieselbe Weise ein.

const created = await client.v2.workspaces.projects.states.create(
"acme",
"ENG",
{ name: "In Review", color: "#4ECDC4" },
{ fields: ["id", "name"] }
);
console.log(created.name); // eingeschränkt; `created.color` würde nicht kompilieren

Zur Laufzeit erstellte Feldlisten​

Eine zur Laufzeit erstellte Feldliste (kein Literal) muss weiterhin als Feldnamen typisiert sein. Ein einfaches string[] ist nicht einem readonly StateField[] zuweisbar und schlägt mit einem langen Overload-Mismatch-Fehler fehl. Die Zeile wird auf den Elementtyp der Liste eingeschränkt, also typisiere die Variable so eng, wie du sie tatsächlich benutzt:

import { PlaneClient, v2 } from "@hoyasumii/plane";

const client = new PlaneClient({ baseUrl: "https://api.plane.so", apiKey: "..." });

// Auf diese zwei Namen eingeschränkt, obwohl der Wert erst zur Laufzeit feststeht.
const wanted: ("id" | "name")[] = includeColor ? ["id", "name"] : ["id"];
const page = await client.v2.workspaces.projects.states.list("acme", "ENG", { fields: wanted });

// Als ganze Union typisiert, schränkt dies auf „jedes Feld“ ein, also die volle Zeile.
const anything: v2.StateField[] = includeColor ? ["id", "name", "color"] : ["id", "name"];
const unnarrowed = await client.v2.workspaces.projects.states.list("acme", "ENG", { fields: anything });

"all" ist ein gültiger Feldwert, der "jedes Feld" bedeutet, und liefert korrekt den vollständigen Zeilentyp.

Spärliche Antworten bedeuten, dass in den Modellen jedes Lesefeld ausser id optional ist. Prüfe auf undefined, statt Anwesenheit anzunehmen. Wenn die Liste dynamisch erstellt wurde, sagt dir row.$loaded.present, was tatsächlich zurückgekommen ist.

Diese Einschränkung ist der Grund, warum die flache Form öffentlich bleibt. Ein navigierter Aufruf löst gegen die allgemeine Signatur auf, akzeptiert also fields, schränkt aber nicht ein:

const eng = await client.v2.workspaces.projects.retrieve("acme", "ENG");
const listed = await eng.states.list({ fields: ["id", "name"] }); // Page<State>, nicht eingeschränkt

TypeScript löscht einen Typparameter, wenn es ihn durch den bedingten Typ hinter einer Navigationseigenschaft ableitet, sodass der einschränkende Overload nicht mitgeführt werden kann. Den Overload-Satz stattdessen abzugleichen wäre schlechter, nicht besser: Die Ableitung würde F auf seine Beschränkung löschen und behaupten, jedes Feld sei vorhanden. Wenn du die eingeschränkte Zeile willst, rufe die Ressource flach auf: client.v2.workspaces.projects.states.list("acme", "ENG", { fields: [...] }).

expand und order_by​

expand fügt verwandte Objekte inline ein ({ expand: ["state", "labels"] } bei einem Work Item), validiert gegen die erlaubten Werte der Operation in v2.EXPAND.

order_by wird auf dieselbe Weise validiert wie fields, gegen eine generierte Union (StateOrderBy, LabelOrderBy, …). Ein Literal ausserhalb dieser Union ist ein Compile-Fehler, und ein zur Laufzeit erstellter Wert wird clientseitig von encodeOrderBy abgelehnt, statt als 400 den Server zu erreichen.

await client.v2.workspaces.projects.states.list("acme", "ENG", { order_by: "-created_at" });