リンゴとナシがあります。どちらも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: (value: Apple, index: number, array: Apple[]) => any, thisArg?: any) => Apple[]) | ...' には互換性のある呼び出しシグネチャがありません。
ここで何が問題なのでしょうか。Typescript が新鮮な果物を好まないだけなのでしょうか、それともこれは Typescript のバグなのでしょうか。
公式のタイプスクリプトのRepl。
ベストアンサー1
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[]
。