So vermeiden Sie dynamische Fehler beim Zuweisen von Objektschlüsseln in TypeScript

8

Angenommen, wir haben TypeScript-Code, der wie folgt aussieht:

type User = {
  id: number,
  name: string,
}

let user1: User = {id: 123, name: "Hello"};
let user2: User = {id: 456, name: "World"};

let keys: (keyof User)[] = ["id", "name"];

for (let key of keys) {
  user1[key] = user2[key];
}

Dies gibt einen Fehler

Type 'string | number' is not assignable to type 'never'.

für die Aussage

user1[key] = user2[key];

Wenn wir die Definition von keyszu ändern

let keys: string[] = ["id", "name"];

Der Fehler verschwindet, aber wir verlieren die Typensicherheit.

Gibt es eine Möglichkeit, diesen Fehler zu vermeiden, während die Typensicherheit erhalten bleibt?

Vaibhav K.
quelle
1
let keys: string[]entfernt den Fehler, führt aber einen anderen ein, da TS dies nicht garantieren kann user1[key]oder user2[key]gültig ist.
VLAZ
@VLAZ Ja, let keys: string[]führt ein weiteres Problem ein, aber das wäre ein Laufzeitfehler (wenn das Array zufällig einen nicht vorhandenen Feldnamen als Wert enthält). Was wir suchen, ist eine Überprüfung der Kompilierungszeit, um dies zu vermeiden.
Vaibhav K

Antworten:

5

Es gibt hier keine gute Möglichkeit, eine Typzusicherung zu vermeiden. In der neueren Version von TS (Post 3.5, glaube ich) muss der geschriebene Wert beim Schreiben durch einen Index mit allen möglichen Eigenschaftswerten kompatibel sein, die vom Schlüssel angegeben werden. In Ihrem Fall würde sich number & stringdas auf neverden Fehler reduzieren .

Die Hauptursache ist, dass TS nicht nur Variablen von Typen verfolgt. Was die Typen betrifft, unterscheidet sich Ihr Beispiel nicht von:

let key1 = 'id' as  keyof User;
let key2 = 'name' as  keyof User;
//Obvious error
user1[key1] = user2[key2] // same error, TS can't distingusih between this and your user1[key] = user2[key]

Die einfachste Lösung besteht darin, eine Typzusicherung zu verwenden, wenn Sie, wie in Ihrem Fall, sicher sind, dass dies in Ordnung ist:

type User = {
  id: number,
  name: string,
}


let user1: User = { id: 123, name: "Hello" };
let user2: User = { id: 456, name: "World" };
for (let key of keys) {
  user1[key] = user2[key] as never
}

abspielen

Alternativ (aber nicht mehr typsicher) können Sie eine kleine Lücke verwenden, die dem T[K]Indexwert zugewiesen werden kann:

type User = {
  id: number,
  name: string,
}


let user1: User = { id: 123, name: "Hello" };
let user2: User = { id: 456, name: "World" };

let keys: (keyof User)[] = ["id", "name"];

for (let key of keys) {
  set(user1, key, user2[key])
}

abspielen

Tizian Cernicova-Dragomir
quelle
Danke für die Antwort. Obwohl nicht ideal, as neverfunktioniert. Können Sie die setMethode auch im zweiten Beispiel erläutern ?
Vaibhav K