Zum Inhalt springen
aviral gupta

// B2.5 · ca. 38 Min. · Einstieg

Literaltypen und as const; Projekt: ein typisiertes Adressbuch

Nach dieser Lektion erlauben Sie nur wenige exakte Werte, sagen voraus, wann TypeScript ein Literal erweitert, und bauen ein typisiertes Adressbuch.

Lektion 5 von 5 in B2 Alltägliche Typen

Ende des Moduls

Danach können Sie

  • Literaltypen und Unions von Literalen schreiben und die Fehler lesen, die tsc für andere Werte meldet
  • Vorhersagen, wann TypeScript einen Literaltyp erweitert, und ihn mit as "GET" oder as const behalten
  • Ein typisiertes Adressbuch mit Interface, optionaler Eigenschaft, Literal-Union und as-const-Liste bauen
  1. Aufwärmen · Aufgabe 1 von 7

    Aus diesem Modul: Was davon trifft zu? Wählen Sie alle zutreffenden.

    Wählen Sie alle zutreffenden aus.

  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen: alignment nimmt nur drei exakte Strings an. Was meldet tsc?

    function printText(s: string, alignment: "left" | "right" | "center") {
      console.log(s + " (" + alignment + ")");
    }
    
    printText("Hello, world", "left");
    printText("G'day, mate", "centre");
  3. Üben · Aufgabe 3 von 7

    Ergänzen Sie die zwei Wörter hinter dem Objektliteral, die method als Literaltyp "GET" behalten, damit tsc den Aufruf akzeptiert.

    function handleRequest(url: string, method: "GET" | "POST") {
      console.log(method + " " + url);
    }
    
    const req = { url: "https://example.com", method: "GET" } ____;
    handleRequest(req.url, req.method);
    const req = { url: "https://example.com", method: "GET" } ;
  4. Üben · Aufgabe 4 von 7

    Welchen Typ leitet TypeScript für greeting ab?

    const greeting = "Hello";
    let other = "Hello";
  5. Üben · Aufgabe 5 von 7

    Ordnen Sie jeder Deklaration den Typ zu, den TypeScript ableitet.

  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. settings ist eine const. Was meldet tsc für Zeile 2?

    const settings = { theme: "dark" };
    settings.theme = "light";
    console.log(settings.theme);
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe. Deklarieren Sie type Theme = "light" | "dark" und eine Funktion background(theme: Theme), die für dark "#222222" und sonst "#ffffff" zurückgibt. Speichern Sie eine Einstellung als Objekt { user: "ada", theme: "dark" } und übergeben Sie saved.theme an background. Lesen Sie zuerst den Fehler von tsc und beheben Sie ihn dann mit as const. Probieren Sie zum Schluss background("blue") aus.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Eine Preisliste mit ausgerichteten Spalten

pad nimmt als Ausrichtung nur "left" oder "right" an. Die Einstellungen jeder Spalte stehen in einem Objekt mit as const, also behält align seinen Literaltyp und kann an pad übergeben werden. total ist ein let, also leitet TypeScript number ab, und es kann in der Schleife wachsen. Führen Sie npx tsc aus, dann node main.ts. Entfernen Sie danach ein as const und lesen Sie, was tsc sagt, oder übergeben Sie "middle" an pad.

main.ts

// Literal types: only these exact values fit.
type Align = "left" | "right";

function pad(text: string, width: number, align: Align): string {
  return align === "left" ? text.padEnd(width, ".") : text.padStart(width, ".");
}

// as const keeps "left" and "right" as literal types, not string.
const nameColumn = { width: 10, align: "left" } as const;
const priceColumn = { width: 8, align: "right" } as const;

function row(name: string, price: string): string {
  return pad(name, nameColumn.width, nameColumn.align) + pad(price, priceColumn.width, priceColumn.align);
}

const items = [
  { name: "Tea", price: 2.5 },
  { name: "Cake", price: 3.75 },
];

let total = 0; // let: TypeScript infers number, so it can change
for (const item of items) {
  console.log(row(item.name, item.price.toFixed(2)));
  total += item.price;
}
console.log(row("Total", total.toFixed(2)));

Ausführen mit

npx tsc
node main.ts

Ausgabe

Tea...........2.50
Cake..........3.75
Total.........6.25
  • Ohne as const wäre nameColumn.align ein string, und pad(…, nameColumn.align) wäre error TS2345.
  • items hat keine Annotation: TypeScript leitet { name: string; price: number; }[] aus den Literalen ab.
  • Auch der Vergleich mit === in pad wird geprüft: align === "centre" wäre error TS2367.
  • Die Literaltypen gibt es nur für tsc: Node.js entfernt sie, und die Ausgabe ist die von einfachem JavaScript.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 3

tsc den Tippfehler finden lassen

Dieses Programm soll Express: 9.90 EUR ausgeben, gibt aber 4.90 aus, und tsc meldet nichts: speed ist ein string, also wird der Tippfehler "expres" angenommen und still wie standard behandelt. Ändern Sie den Typ von speed in eine Union der beiden String-Literale "standard" und "express". Dann meldet tsc den Tippfehler: Beheben Sie ihn.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Eine Union von Literalen schreibt man mit | zwischen den Werten: "a" | "b".

  2. Hinweis 2

    Die erste Zeile wird zu export function shippingCost(speed: "standard" | "express"): number {

  3. Hinweis 3

    tsc meldet dann Argument of type '"expres"' in Zeile 5. Schreiben Sie "express".

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function shippingCost(speed: "standard" | "express"): number {
  return speed === "express" ? 9.9 : 4.9;
}

console.log("Express: " + shippingCost("express").toFixed(2) + " EUR");
console.log("Standard: " + shippingCost("standard").toFixed(2) + " EUR");
Auf dem eigenen Computer ausführen

Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.ts

export function shippingCost(speed: string): number {
  return speed === "express" ? 9.9 : 4.9;
}

console.log("Express: " + shippingCost("expres").toFixed(2) + " EUR");
console.log("Standard: " + shippingCost("standard").toFixed(2) + " EUR");

main.test.ts

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
import {shippingCost} from './main.ts';

test('shippingCost("express") ist 9.9', () => {
  assert.equal(shippingCost('express'), 9.9, 'shippingCost("express") sollte 9.9 sein');
});

test('shippingCost("standard") ist 4.9', () => {
  assert.equal(shippingCost('standard'), 4.9, 'shippingCost("standard") sollte 4.9 sein');
});

test('das Programm gibt beide Preise aus', async () => {
  const out = (await runMain()).trimEnd();
  assert.equal(out, 'Express: 9.90 EUR\nStandard: 4.90 EUR', `das Programm gab ${JSON.stringify(out)} aus`);
});

package.json

{
  "type": "module"
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "lib": [
      "esnext",
      "dom"
    ],
    "types": [],
    "strict": true,
    "noEmit": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "**/*.test.ts"
  ]
}

npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.

Programm ausführen:

npx tsc
node main.ts

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

npx tsc
node --test
learnrun.js herunterladen

Übung 2 von 3

Die Methode als Literal behalten

request nimmt nur "GET" oder "POST" an, und das Programm gibt die richtigen Zeilen aus, aber tsc meldet zweimal Argument of type 'string' is not assignable to parameter of type '"GET" | "POST"'. Beheben Sie es dort, wo die Objekte entstehen, nicht in den Aufrufen und nicht in der Funktion: Behalten Sie jede Methode als Literaltyp.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Objekteigenschaften werden erweitert: home.method ist string, nicht "GET", weil sie noch zugewiesen werden könnte.

  2. Hinweis 2

    Zwei Wörter hinter der schließenden Klammer eines Objektliterals machen jede Eigenschaft zu ihrem Literaltyp.

  3. Hinweis 3

    Schreiben Sie const home = { url: "/home", method: "GET" } as const; und dasselbe für login.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function request(url: string, method: "GET" | "POST"): string {
  return method + " " + url;
}

const home = { url: "/home", method: "GET" } as const;
const login = { url: "/login", method: "POST" } as const;
console.log(request(home.url, home.method));
console.log(request(login.url, login.method));
Auf dem eigenen Computer ausführen

Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.ts

export function request(url: string, method: "GET" | "POST"): string {
  return method + " " + url;
}

const home = { url: "/home", method: "GET" };
const login = { url: "/login", method: "POST" };
console.log(request(home.url, home.method));
console.log(request(login.url, login.method));

main.test.ts

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
import {request} from './main.ts';

test('request verbindet Methode und URL', () => {
  assert.equal(request('/cart', 'POST'), 'POST /cart', 'request("/cart", "POST") sollte POST /cart sein');
});

test('das Programm gibt beide Anfragen aus', async () => {
  const out = (await runMain()).trimEnd();
  assert.equal(out, 'GET /home\nPOST /login', `das Programm gab ${JSON.stringify(out)} aus`);
});

package.json

{
  "type": "module"
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "lib": [
      "esnext",
      "dom"
    ],
    "types": [],
    "strict": true,
    "noEmit": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "**/*.test.ts"
  ]
}

npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.

Programm ausführen:

npx tsc
node main.ts

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

npx tsc
node --test
learnrun.js herunterladen

Übung 3 von 3

Projekt: ein typisiertes Adressbuch

Das Modulprojekt. Das Adressbuch unten läuft, aber tsc meldet viele Fehler, und die Funktionen sind leer. Deklarieren Sie type Kind ("friend", "work" oder "family") und interface Contact (name und email als Strings, ein optionales phone, kind als Kind, favorite als boolean). Machen Sie KINDS zu einer as-const-Liste und geben Sie ada einen Typ, damit tsc beide akzeptiert. Schreiben Sie dann die Funktionen: formatContact liefert * Ada Lovelace <ada@example.com> (work, no phone), mit "* " nur für Favoriten und der Telefonnummer, wenn es eine gibt; byKind behält die Kontakte einer Art; favorites liefert deren Namen. Die Tests prüfen jede Funktion und das ausgegebene Adressbuch.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Beginnen Sie mit den Typen: type Kind = "friend" | "work" | "family"; und einem interface Contact mit phone?: string.

  2. Hinweis 2

    Bei ada wird kind zu string erweitert, ebenso jedes Element von KINDS. Schreiben Sie const ada: Contact = … und setzen Sie as const hinter das KINDS-Array.

  3. Hinweis 3

    contact.phone ?? "no phone" liefert den Standardwert. byKind ist book.filter((contact) => contact.kind === kind); favorites filtert nach favorite und bildet dann auf den Namen ab.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

// A typed contact book. Declare the types, then finish the functions.

type Kind = "friend" | "work" | "family";

interface Contact {
  name: string;
  email: string;
  phone?: string;
  kind: Kind;
  favorite: boolean;
}

export const KINDS = ["friend", "work", "family"] as const;

export function formatContact(contact: Contact): string {
  const star = contact.favorite ? "* " : "";
  const phone = contact.phone ?? "no phone";
  return star + contact.name + " <" + contact.email + "> (" + contact.kind + ", " + phone + ")";
}

export function byKind(book: Contact[], kind: Kind): Contact[] {
  return book.filter((contact) => contact.kind === kind);
}

export function favorites(book: Contact[]): string[] {
  return book.filter((contact) => contact.favorite).map((contact) => contact.name);
}

export function summary(book: Contact[]): string {
  const parts: string[] = [];
  for (const kind of KINDS) {
    parts.push(kind + ": " + byKind(book, kind).length);
  }
  return parts.join(", ");
}

const ada: Contact = { name: "Ada Lovelace", email: "ada@example.com", kind: "work", favorite: true };

const book: Contact[] = [
  ada,
  { name: "Grace Hopper", email: "grace@example.com", phone: "+49 30 1234567", kind: "work", favorite: false },
  { name: "Linus Torvalds", email: "linus@example.com", kind: "friend", favorite: true },
];

for (const contact of book) {
  console.log(formatContact(contact));
}
console.log(summary(book));
console.log("Favorites: " + favorites(book).join(", "));
Auf dem eigenen Computer ausführen

Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.ts

// A typed contact book. Declare the types, then finish the functions.

// 1. Kind: "friend", "work" or "family".
// 2. Contact: name and email (text), phone (optional text), kind (a Kind),
//    favorite (true or false).

export const KINDS = ["friend", "work", "family"];

export function formatContact(contact: Contact): string {
  // "* Ada Lovelace <ada@example.com> (work, no phone)"; only favorites start with "* "
  return "";
}

export function byKind(book: Contact[], kind: Kind): Contact[] {
  return [];
}

export function favorites(book: Contact[]): string[] {
  // the names of every favorite, in book order
  return [];
}

export function summary(book: Contact[]): string {
  // "friend: 1, work: 2, family: 0", in the order of KINDS
  const parts: string[] = [];
  for (const kind of KINDS) {
    parts.push(kind + ": " + byKind(book, kind).length);
  }
  return parts.join(", ");
}

const ada = { name: "Ada Lovelace", email: "ada@example.com", kind: "work", favorite: true };

const book: Contact[] = [
  ada,
  { name: "Grace Hopper", email: "grace@example.com", phone: "+49 30 1234567", kind: "work", favorite: false },
  { name: "Linus Torvalds", email: "linus@example.com", kind: "friend", favorite: true },
];

for (const contact of book) {
  console.log(formatContact(contact));
}
console.log(summary(book));
console.log("Favorites: " + favorites(book).join(", "));

main.test.ts

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {runMain} from './learnrun.js';
import {formatContact, byKind, favorites, summary} from './main.ts';

const ada = {name: 'Ada', email: 'ada@example.com', kind: 'work', favorite: true};
const bob = {name: 'Bob', email: 'bob@example.com', phone: '555-0100', kind: 'family', favorite: false};
const cy = {name: 'Cy', email: 'cy@example.com', kind: 'work', favorite: false};
const book = [ada, bob, cy];

test('formatContact markiert einen Favoriten ohne Telefon', () => {
  const line = formatContact(ada);
  assert.equal(line, '* Ada <ada@example.com> (work, no phone)', `formatContact(ada) lieferte ${JSON.stringify(line)}`);
});

test('formatContact zeigt das Telefon eines Kontakts, der kein Favorit ist', () => {
  const line = formatContact(bob);
  assert.equal(line, 'Bob <bob@example.com> (family, 555-0100)', `formatContact(bob) lieferte ${JSON.stringify(line)}`);
});

test('byKind behält nur die Kontakte dieser Art', () => {
  const names = byKind(book, 'work').map((contact) => contact.name);
  assert.deepEqual(names, ['Ada', 'Cy'], `byKind(book, 'work') lieferte ${JSON.stringify(names)}`);
  assert.equal(byKind(book, 'friend').length, 0, 'byKind(book, "friend") sollte leer sein');
});

test('favorites liefert die Namen der Favoriten', () => {
  const names = favorites(book);
  assert.deepEqual(names, ['Ada'], `favorites(book) lieferte ${JSON.stringify(names)}`);
});

test('summary zählt jede Art', () => {
  const text = summary(book);
  assert.equal(text, 'friend: 0, work: 2, family: 1', `summary(book) lieferte ${JSON.stringify(text)}`);
});

test('das Programm gibt das ganze Adressbuch aus', async () => {
  const out = (await runMain()).trimEnd();
  assert.equal(
    out,
    '* Ada Lovelace <ada@example.com> (work, no phone)\nGrace Hopper <grace@example.com> (work, +49 30 1234567)\n* Linus Torvalds <linus@example.com> (friend, no phone)\nfriend: 1, work: 2, family: 0\nFavorites: Ada Lovelace, Linus Torvalds',
    `das Programm gab ${JSON.stringify(out)} aus`
  );
});

package.json

{
  "type": "module"
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "lib": [
      "esnext",
      "dom"
    ],
    "types": [],
    "strict": true,
    "noEmit": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "**/*.test.ts"
  ]
}

npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.

Programm ausführen:

npx tsc
node main.ts

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

npx tsc
node --test
learnrun.js herunterladen

Häufige Fehler

Ein Wert knapp außerhalb der Literal-Union

function printText(s: string, alignment: "left" | "right" | "center") {
  console.log(s);
}

printText("Price list", "centre");

Was tsc oder Node.js ausgibt

main.ts(5,25): error TS2345: Argument of type '"centre"' is not assignable to parameter of type '"center" | "left" | "right"'.

Warum, und die Lösung

Eine Literal-Union erlaubt genau die Werte, die sie aufzählt, genau so geschrieben. tsc nennt den gefundenen Wert, "centre", und die Werte, die es annimmt. Schreiben Sie "center". Genau dafür ist eine Literal-Union da: In einfachem JavaScript liefe der Tippfehler und fiele still durch jede Prüfung auf "center".

Eine zu string erweiterte Eigenschaft

type Mode = "light" | "dark";

let mode: Mode = "light";
const saved = { mode: "dark" };
mode = saved.mode;

Was tsc oder Node.js ausgibt

main.ts(5,1): error TS2322: Type 'string' is not assignable to type 'Mode'.

Warum, und die Lösung

saved.mode enthält "dark", aber sein Typ ist string: Eine Objekteigenschaft kann noch zugewiesen werden, also erweitert TypeScript sie. string ist weiter als Mode, also lehnt tsc ab. Behalten Sie das Literal dort, wo das Objekt entsteht: const saved = { mode: "dark" } as const;, oder annotieren Sie es: const saved: { mode: Mode } = { mode: "dark" };.

Eine Liste mit as const verändern

const KINDS = ["friend", "work"] as const;
KINDS.push("family");

Was tsc oder Node.js ausgibt

main.ts(2,7): error TS2339: Property 'push' does not exist on type 'readonly ["friend", "work"]'.

Warum, und die Lösung

as const macht ein Array zu einem readonly-Tupel: genau diese Elemente, in dieser Reihenfolge, und keine Methode, die es verändert, etwa push. Für eine feste Liste von Arten ist das gewollt. Muss die Liste wachsen, ergänzen Sie "family" im Literal selbst, oder lassen Sie as const weg und annotieren Sie sie, etwa const kinds: string[] = ["friend", "work"].

TypeScript im Browser: der Compiler von TypeScript 6.0.3, Apache-2.0, danach die eigene Engine Ihres Browsers. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Literaltypen: ein exakter Wert als Typ

Neben string und number kann ein Typ auch ein exakter Wert sein: let x: "hello" nimmt nur den Text "hello" an, also ist x = "howdy" error TS2322. Ein einzelner Wert ist selten nützlich, eine Union von Literalen schon. function printText(s: string, alignment: "left" | "right" | "center") nimmt genau diese drei Strings an, und der Tippfehler "centre" ist error TS2345. Zahl-Literale funktionieren genauso: 1 | 2 | 3. boolean selbst ist die Union true | false. Benennen Sie eine Union, die Sie mehrfach brauchen: type Kind = "friend" | "work" | "family". Sie prüft auch Vergleiche: kind === "wrok" ist error TS2367, weil ein Kind nie gleich diesem Wert sein kann. Unions allgemein kommen in Modul B3.

const behält das Literal, let erweitert es

TypeScript leitet einen Literaltyp nur dort ab, wo sich der Wert nicht ändern kann. const greeting = "Hello" hat den Typ "Hello": Eine const enthält immer genau diesen String. let other = "Hello" hat den Typ string, weil die Variable später jeden anderen String bekommen kann; ebenso ist let count = 3 eine number und const limit = 3 hat den Typ 3. Objekteigenschaften verhalten sich wie let. In const req = { url: "/home", method: "GET" } ist req.method ein string, weil die Eigenschaft noch zugewiesen werden kann: const legt die Variable fest, nicht den Inhalt des Objekts. req.method an einen Parameter vom Typ "GET" | "POST" zu übergeben, ist daher error TS2345.

Zwei Lösungen: as "GET" und as const

Eine Assertion an einer Eigenschaft, method: "GET" as "GET", behält deren Literaltyp, also ist eine spätere Zuweisung von "GUESS" error TS2322. as const hinter dem ganzen Literal gibt jeder Eigenschaft ihren Literaltyp und macht sie readonly: { url: "/home", method: "GET" } as const hat den Typ { readonly url: "/home"; readonly method: "GET"; }. Ein Array wird zu einem readonly-Tupel: ["friend", "work", "family"] as const, also ist push darauf error TS2339, und jedes Element behält seinen Literaltyp. Ein dritter Weg ist eine Annotation: const ada: Contact = { … } prüft das Literal direkt gegen Contact. Nichts davon ändert die Werte zur Laufzeit; as const informiert nur die Typprüfung.

Quellen

Zuletzt geprüft am 3. Oktober 2026