Aufwärmen · Aufgabe 1 von 7
Aufwärmen mit JavaScript: copy ist ein weiterer Name für scores. Was gibt das aus?
const scores = [70, 85];
const copy = scores;
copy.push(99);
console.log(scores.length);// B5.4 · ca. 30 Min. · Einstieg
Nach dieser Lektion schützen Sie Arrays mit readonly vor Änderungen und typisieren Daten mit festen Positionen als Tupel.
Danach können Sie
Aufwärmen · Aufgabe 1 von 7
const scores = [70, 85];
const copy = scores;
copy.push(99);
console.log(scores.length);Vorhersagen · Aufgabe 2 von 7
function report(scores: readonly number[]): number {
const best = scores.toSorted((a, b) => b - a);
best.push(0);
scores.push(0);
return best[0];
}Üben · Aufgabe 3 von 7
function total(prices: ____ number[]): number {
// @ts-expect-error: total must not change the prices
prices.push(0);
let sum = 0;
for (const p of prices) sum += p;
return sum;
}
console.log(total([2, 3.5]));Üben · Aufgabe 4 von 7
let editable: string[] = ["a", "b"];
let locked: readonly string[] = ["c"];
locked = editable;
editable = locked;Üben · Aufgabe 5 von 7
function setCoordinate(coord: [number, number, number?]) {
const [x, y, z] = coord;
const n = coord.length;
// here
return x + y + (z ?? 0) + n;
}Denksport · Aufgabe 6 von 7
const pair: [string, number] = ["Ada", 36];
pair.push(1815);
console.log(pair.length, pair);Anwenden · Aufgabe 7 von 7
Prüfen Sie Ihr Ergebnis anhand dieser Liste
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
Ein Reading ist ein readonly-Tupel: zuerst die Uhrzeit, dann die Temperatur. Die Liste der Messungen ist ebenfalls readonly, und warmest verspricht in seinem Parameter, sie nicht zu ändern, sortiert also mit toSorted eine Kopie. range nimmt ein Tupel, dessen Einheit fehlen darf; week hat ein Label, gefolgt von beliebig vielen Werten; units entsteht mit as const. Führen Sie npx tsc aus, dann node main.ts. Fügen Sie dann readings.push(["21:00", 14]); und week[0] = 1; hinzu und führen Sie tsc erneut aus.
main.ts
// A reading has two fixed positions: the time, then the temperature.
type Reading = readonly [string, number];
// Once loaded, the readings must not change: readonly on the array too.
const readings: readonly Reading[] = [
["06:00", 11.5],
["12:00", 19],
["18:00", 16.5]
];
// readonly in the parameter: this function promises not to change the list.
function warmest(list: readonly Reading[]): Reading {
const sorted = list.toSorted((a, b) => b[1] - a[1]); // a new, mutable copy
return sorted[0];
}
// An optional last element: the unit may be left out.
function range(r: [number, number, string?]): string {
const [min, max, unit = "C"] = r;
return min + " to " + max + " " + unit + " (" + r.length + " elements)";
}
// A rest element: a label, then any number of values.
const week: [string, ...number[]] = ["Mon", 11.5, 19, 16.5];
const [label, ...values] = week;
// as const: a readonly tuple of literal types.
const units = ["C", "F"] as const;
const [time, temp] = warmest(readings);
console.log("warmest: " + temp + " at " + time);
console.log(range([11.5, 19]));
console.log(range([52.7, 66.2, "F"]));
console.log(label + ": " + values.length + " values");
console.log(units.join(" or "), readings.length);
Ausführen mit
npx tsc
node main.tsAusgabe
warmest: 19 at 12:00
11.5 to 19 C (2 elements)
52.7 to 66.2 F (3 elements)
Mon: 3 values
C or F 3Tab 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.
Übung 1 von 2
median sortiert das übergebene Array, also ändert sich die Reihenfolge im Array des Aufrufers, und das // @ts-expect-error in noEdits ist unbenutzt, weil Values push erlaubt. Machen Sie Values zu einem readonly-Array von Zahlen. tsc lehnt dann values.sort ab: Sortieren Sie stattdessen mit toSorted eine Kopie. Behandeln Sie außerdem eine gerade Anzahl von Werten: Der Median ist dann der Durchschnitt der beiden mittleren Werte, median([4, 1, 3, 2]) ist also 2.5. Führen Sie die Tests aus: Der erste ist die Typprüfung.
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.
Der Modifikator readonly steht vor dem Array-Typ: export type Values = readonly number[];
toSorted funktioniert wie sort, gibt aber ein neues Array zurück: const sorted = values.toSorted((a, b) => a - b);
Mit mid = Math.floor(sorted.length / 2) nimmt eine gerade Länge (sorted[mid - 1] + sorted[mid]) / 2.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export type Values = readonly number[];
export function median(values: Values): number {
const sorted = values.toSorted((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) return (sorted[mid - 1] + sorted[mid]) / 2;
return sorted[mid];
}
function noEdits(values: Values) {
// @ts-expect-error: Values is read-only
values.push(0);
}
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 type Values = number[];
export function median(values: Values): number {
values.sort((a, b) => a - b);
return values[Math.floor(values.length / 2)];
}
function noEdits(values: Values) {
// @ts-expect-error: Values is read-only
values.push(0);
}
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {median} from './main.ts';
test('der Median einer ungeraden Anzahl von Werten ist der mittlere', () => {
const got = median([5, 1, 3]);
assert.equal(got, 3, `median([5, 1, 3]) ergab ${got}`);
});
test('der Median einer geraden Anzahl von Werten ist der Durchschnitt der beiden mittleren', () => {
const got = median([4, 1, 3, 2]);
assert.equal(got, 2.5, `median([4, 1, 3, 2]) ergab ${got}`);
});
test('median lässt die Reihenfolge im Array des Aufrufers unverändert', () => {
const values = [5, 1, 3];
median(values);
assert.deepEqual(values, [5, 1, 3], `nach median ist das Array ${JSON.stringify(values)}`);
});
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.tsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
npx tsc
node --testlearnrun.js herunterladenÜbung 2 von 2
Eine Row ist der Name eines Spielers, gefolgt von beliebig vielen Punktzahlen, aber (string | number)[] sagt nicht, was zuerst kommt, also ergibt das Zerlegen string | number, und tsc meldet error TS2322 für player. Machen Sie Row zu einem Tupel mit Rest-Element, sodass das // @ts-expect-error bei der leeren Zeile seinen Fehler findet. Lassen Sie bestScore ein readonly [string, number] zurückgeben, sodass auch das Schreiben in top[1] gemeldet wird. Ein Spieler ohne Punktzahlen bekommt 0 als beste Punktzahl.
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.
Ein Rest-Element steht als letztes in den Klammern: [string, ...number[]] ist ein String, gefolgt von beliebig vielen Zahlen.
Setzen Sie readonly vor den Rückgabetyp: function bestScore(row: Row): readonly [string, number] {
Math.max() ohne Argumente ergibt -Infinity, prüfen Sie also zuerst scores.length === 0 und geben Sie [player, 0] zurück.
Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.
export type Row = [string, ...number[]];
export function bestScore(row: Row): readonly [string, number] {
const [player, ...scores] = row;
if (scores.length === 0) return [player, 0];
return [player, Math.max(...scores)];
}
// @ts-expect-error: a row starts with the player's name
const empty: Row = [];
const top = bestScore(["Ada", 9]);
// @ts-expect-error: the result is read-only
top[1] = 10;
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 type Row = (string | number)[];
export function bestScore(row: Row): [string, number] {
const [player, ...scores] = row;
return [player, Math.max(...scores)];
}
// @ts-expect-error: a row starts with the player's name
const empty: Row = [];
const top = bestScore(["Ada", 9]);
// @ts-expect-error: the result is read-only
top[1] = 10;
main.test.ts
import {test} from 'node:test';
import assert from 'node:assert/strict';
import {bestScore} from './main.ts';
test('die beste Punktzahl kommt zusammen mit dem Spieler', () => {
const got = bestScore(['Ada', 3, 9, 4]);
assert.deepEqual(got, ['Ada', 9], `bestScore(['Ada', 3, 9, 4]) ergab ${JSON.stringify(got)}`);
});
test('negative Punktzahlen zählen auch', () => {
const got = bestScore(['Cy', -2, -5]);
assert.deepEqual(got, ['Cy', -2], `bestScore(['Cy', -2, -5]) ergab ${JSON.stringify(got)}`);
});
test('ein Spieler ohne Punktzahlen bekommt 0', () => {
const got = bestScore(['Bob']);
assert.deepEqual(got, ['Bob', 0], `bestScore(['Bob']) ergab ${JSON.stringify(got)}`);
});
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.tsPrüfungen ausführen (learnrun.js muss im selben Ordner liegen):
npx tsc
node --testlearnrun.js herunterladenconst tags: readonly string[] = ["news", "tech"];
tags.push("sport");
Was tsc oder Node.js ausgibt
main.ts(2,6): error TS2339: Property 'push' does not exist on type 'readonly string[]'.Warum, und die Lösung
Ein readonly-Array-Typ hat keine Methoden, die ihn ändern, push ist also schlicht nicht vorhanden. Muss die Liste wirklich wachsen, machen Sie sie zu einem string[]. Soll sie bleiben, wie sie ist, bauen Sie ein neues Array: const more = [...tags, "sport"]; oder tags.concat("sport"). Beides lässt tags unverändert und gibt Ihnen ein neues, veränderbares Array.
const roles = ["admin", "editor"] as const;
const list: string[] = roles;
Was tsc oder Node.js ausgibt
main.ts(2,7): error TS4104: The type 'readonly ["admin", "editor"]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.Warum, und die Lösung
as const macht roles zu einem readonly-Tupel, und ein string[] würde darauf push und sort erlauben. Lesen Sie die Liste nur, typisieren Sie sie ebenfalls als readonly string[]. Müssen Sie sie ändern, kopieren Sie sie: const list: string[] = [...roles];. Die Kopie ist ein neues Array, roles bleibt also, wie es war.
const pair = ["Ada", 36];
const person: [string, number] = pair;
Was tsc oder Node.js ausgibt
main.ts(2,7): error TS2322: Type '(string | number)[]' is not assignable to type '[string, number]'.Warum, und die Lösung
Ohne Tupeltyp inferiert tsc ein gewöhnliches Array, (string | number)[], das jede Länge und jede Reihenfolge von Strings und Zahlen haben könnte. Die nächste Zeile sagt es: Target requires 2 element(s) but source may have fewer. Annotieren Sie dort, wo der Wert entsteht, const pair: [string, number] = ["Ada", 36], oder nehmen Sie as const, wenn er sich nie ändert.
TypeScript im Browser: der Compiler von TypeScript 6.0.3, Apache-2.0, danach die eigene Engine Ihres Browsers. Lizenz und Quellcode
5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.
Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.