Ich habe Apfel und Birnen - beide haben ein isDecayed
Attribut:
interface Apple {
color: string;
isDecayed: boolean;
}
interface Pear {
weight: number;
isDecayed: boolean;
}
Und beide Sorten können (mehrmals) in meinem Obstkorb sein:
interface FruitBasket {
apples: Apple[];
pears: Pear[];
}
Nehmen wir an, mein Korb ist vorerst leer:
const fruitBasket: FruitBasket = { apples: [], pears: [] };
Jetzt nehmen wir zufällig eine Sorte aus dem Korb:
const key: keyof FruitBasket = Math.random() > 0.5 ? 'apples': 'pears';
const fruits = fruitBasket[key];
Und natürlich mag niemand verfallene Früchte, also pflücken wir nur die frischen:
const freshFruits = fruits.filter((fruit) => !fruit.isDecayed);
Leider sagt mir Typescript:
Ein Ausdruck, dessen Typ keine Anrufsignatur hat, kann nicht aufgerufen werden. Geben Sie '((callbackfn: (Wert: Apple, Index: Nummer, Array: Apple []) => any, thisArg?: Any) => Apple []) | ein ... 'hat keine kompatiblen Rufsignaturen.
Was ist hier falsch - ist es nur so, dass Typescript keine frischen Früchte mag oder ist dies ein Typescript-Fehler?
Sie können es selbst im offiziellen Typescript Repl versuchen .
javascript
typescript
types
Erdem
quelle
quelle
Fruit
Schnittstelle mit derisDecayed
Eigenschaft nicht erweitern und dann Früchte als vom Typ deklarieren könnenFruit[]
?key
aufstring
ieconst key: string = Math.random() > 0.5 ? 'apples': 'pears';
any
das Problem umgeht.Antworten:
TypeScript unterstützt die strukturelle Typisierung (auch als Ententypisierung bezeichnet). Dies bedeutet, dass Typen kompatibel sind, wenn sie dieselben Mitglieder verwenden . Ihr Problem ist das
Apple
undPear
teilen Sie nicht alle ihre Mitglieder, was bedeutet, dass sie nicht kompatibel sind. Sie sind jedoch mit einem anderen Typ kompatibel, der nur dasisDecayed: boolean
Mitglied hat. Aufgrund der strukturellen Typisierung, Sie don‘Notwendigkeit zu erbenApple
undPear
von einer solchen Schnittstelle.Es gibt verschiedene Möglichkeiten, einen solchen kompatiblen Typ zuzuweisen:
Typ während der Variablendeklaration zuweisen
Diese Anweisung lautet implizit
Apple[] | Pear[]
:const fruits = fruitBasket[key];
Sie können einfach einen kompatiblen Typ explizit in Ihrer Variablendeklaration verwenden:
const fruits: { isDecayed: boolean }[] = fruitBasket[key];
Für zusätzliche Wiederverwendbarkeit können Sie den Typ auch zuerst definieren und dann in Ihrer Deklaration verwenden (beachten Sie, dass die Schnittstellen
Apple
undPear
nicht geändert werden müssen):type Fruit = { isDecayed: boolean }; const fruits: Fruit[] = fruitBasket[key];
Für die Operation auf einen kompatiblen Typ umwandeln
Das Problem mit der angegebenen Lösung besteht darin, dass der Typ der
fruits
Variablen geändert wird. Dies ist möglicherweise nicht das, was Sie wollen. Um dies zu vermeiden, können Sie das Array vor der Operation auf einen kompatiblen Typ eingrenzen und den Typ dann auf denselben Typ zurücksetzen wiefruits
:const fruits: fruitBasket[key]; const freshFruits = (fruits as { isDecayed: boolean }[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
Oder mit dem wiederverwendbaren
Fruit
Typ:type Fruit = { isDecayed: boolean }; const fruits: fruitBasket[key]; const freshFruits = (fruits as Fruit[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
Der Vorteil dieser Lösung besteht darin, dass beide
fruits
undfreshFruits
vom Typ sindApple[] | Pear[]
.quelle
Wie in der Github-Ausgabe erwähnt, die ursprünglich von @peter in den Kommentaren verlinkt wurde:
const freshFruits = (fruits as (Apple | Pear)[]).filter((fruit: (Apple | Pear)) => !fruit.isDecayed);
quelle
Erstellen Sie möglicherweise eine gemeinsam genutzte
Fruit
Schnittstelle, die isDecayed bereitstellt.fruits
ist jetzt vom Typ,Fruit[]
sodass der Typ explizit sein kann. So was:interface Fruit { isDecayed: boolean; } interface Apple extends Fruit { color: string; } interface Pear extends Fruit { weight: number; } interface FruitBasket { apples: Apple[]; pears: Pear[]; } const fruitBasket: FruitBasket = { apples: [], pears: [] }; const key: keyof FruitBasket = Math.random() > 0.5 ? 'apples': 'pears'; const fruits: Fruit[] = fruitBasket[key]; const freshFruits = fruits.filter((fruit) => !fruit.isDecayed);
quelle
FruitBasket
könnten auch nur eine Reihe vonFruit
s seinIch hatte das gleiche Problem mit numeral, einer JS-Bibliothek. Das Update bestand darin, die Typisierungen mit diesem Befehl erneut zu installieren:
quelle