Ich habe eine Schnittstelle wie diese. Und ich frage mich, was der beste Fall ist, um diesen Fall zu behandeln:

interface Ia {
  a: string
}
let a: Ia | Ia[]
console.log(a[0].a)

TS wirft mir einen Fehler:

Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'Ia'.
  Property '0' does not exist on type 'Ia'.

Ich weiß, dass ich console.log((a as Ia[])[0].a) verwenden könnte, aber es ist überhaupt nicht lesbar. Hat jemand bessere Vorschläge?

Außerdem enthält der reale Anwendungsfalltyp viele Eigenschaften, nicht die einzige a: sting wie im Beispiel.

1
Lukas Ignatavičius 7 Feb. 2020 im 14:46

3 Antworten

Beste Antwort

Ich habe mich eingelebt mit:

interface Ia {
  a: string
}
let a: Ia | Ia[]
if (Array.isArray(a)){
  a = [a]
}
console.log(a[0].a)

Vielen Dank an @ kaya3 und @ maciej-sikora für Vorschläge

0
Lukas Ignatavičius 10 Feb. 2020 im 13:58

Wenn a kein Array ist, ist a[0] nicht sinnvoll. Sie müssen testen, ob es sich um ein Array handelt, und es je nach Ergebnis dieses Tests unterschiedlich behandeln.

interface Ia {
  a: string
}

let obj: Ia | Ia[] = { a: 'foo' };

function test(obj: Ia | Ia[]): void {
  console.log(Array.isArray(obj) ? obj[0].a : obj.a);
}

Oder Sie können dieses Muster verwenden, das die Verengung des Kontrollflusstyps ausnutzt:

function test2(obj: Ia | Ia[]): void {
  if (Array.isArray(obj)) { obj = obj[0]; }
  // now obj: Ia is known not to be an array
  console.log(obj.a);
}

Spielplatz Link

2
kaya3 7 Feb. 2020 im 11:50

Ich schlage vor, einen Getter dafür zu erstellen, bedenken Sie:

const getA = (x: Ia | Ia[]) => "a" in x ? x.a : x[0]?.a;

const a = getA({ a: 'I am a' });
const a2 = getA([{ a: 'I am also a ' }]);

Oder vereinheitlichen Sie den Typ und verwenden Sie ihn immer auf die gleiche Weise:

const uniform = (x: Ia | Ia[]): Ia => Array.isArray(a) ? a[0] : a;

Diese Funktion vereinheitlicht unseren Typus von der Gewerkschaft zu einem Mitglied.

0
Maciej Sikora 7 Feb. 2020 im 14:42