私はアップルとナシを持っています - 両方ともisDecayed
属性を持っています:
interface Apple {
color: string;
isDecayed: boolean;
}
interface Pear {
weight: number;
isDecayed: boolean;
}
そして両方のタイプは私のフルーツバスケットに入れることができます(複数回):
interface FruitBasket {
apples: Apple[];
pears: Pear[];
}
今のところ私のバスケットは空だとしましょう。
const fruitBasket: FruitBasket = { apples: [], pears: [] };
今、私たちはバスケットから1種類をランダムに取り出します。
const key: keyof FruitBasket = Math.random() > 0.5 ? 'apples': 'pears';
const fruits = fruitBasket[key];
そしてもちろん、腐った果物が好きな人はいないので、新鮮な果物だけを選びます。
const freshFruits = fruits.filter((fruit) => !fruit.isDecayed);
残念ながらTypeScriptは私に言う:
型が呼び出しシグネチャを欠いている式を呼び出すことはできません。 '((callbackfn:(値:Apple、index:number、配列:Apple [])=> any、thisArg ?: any)=> Apple [])|と入力します。 ... '互換性のあるコールシグネチャがありません。
ここで何が問題なのですか - TypeScriptが新鮮な果物を好まないということですか、それともTypeScriptのバグなのでしょうか。
あなたは公式でそれを自分で試すことができます TypeScript Repl 。
TypeScriptは構造型付け(アヒル型付けとも呼ばれる)をサポートしています。つまり、 型は、同じメンバーを共有する場合 で互換性があります。あなたの問題は、Apple
とPear
がすべてのメンバーを共有しているわけではないということです。しかしながら、それらはisDecayed: boolean
メンバーだけを持つ他の型と互換性があります。構造化型のため、そのようなインタフェースからApple
とPear
を継承する必要はありません。
そのような互換タイプを割り当てるにはさまざまな方法があります。
変数宣言中に型を代入します
このステートメントはApple[] | Pear[]
に暗黙的に型指定されています。
const fruits = fruitBasket[key];
あなたは、あなたの変数宣言の中で明示的に互換型を明示的に使用することができます。
const fruits: { isDecayed: boolean }[] = fruitBasket[key];
再利用性を高めるために、最初に型を定義してから宣言に使用することもできます(Apple
およびPear
インターフェースを変更する必要はありません)。
type Fruit = { isDecayed: boolean };
const fruits: Fruit[] = fruitBasket[key];
操作に対して互換性のある型にキャストされます
与えられた解決策の問題はそれがfruits
変数の型を変更することです。これはあなたが望むものではないかもしれません。これを避けるために、操作の前に配列を互換性のある型に絞り込み、その型をfruits
と同じ型に戻すことができます。
const fruits: fruitBasket[key];
const freshFruits = (fruits as { isDecayed: boolean }[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
あるいは再利用可能なFruit
型を使うと:
type Fruit = { isDecayed: boolean };
const fruits: fruitBasket[key];
const freshFruits = (fruits as Fruit[]).filter(fruit => !fruit.isDecayed) as typeof fruits;
このソリューションの利点は、fruits
とfreshFruits
の両方がApple[] | Pear[]
型になることです。
おそらくisDecayedを提供する共有Fruit
インターフェースを作成してください。 fruits
は現在Fruit[]
型であるため、型を明示的に指定できます。このような:
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);
コメントで@peterによってリンクされていた github issue で述べたように、
const freshFruits = (fruits as (Apple | Pear)[]).filter((fruit: (Apple | Pear)) => !fruit.isDecayed);