web-dev-qa-db-ja.com

型に呼び出しシグネチャがない式を呼び出すことはできません

私はアップルとナシを持っています - 両方とも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

53
Erdem

TypeScriptは構造型付け(アヒル型付けとも呼ばれる)をサポートしています。つまり、 型は、同じメンバーを共有する場合 で互換性があります。あなたの問題は、ApplePearがすべてのメンバーを共有しているわけではないということです。しかしながら、それらはisDecayed: booleanメンバーだけを持つ他の型と互換性があります。構造化型のため、そのようなインタフェースからApplePearを継承する必要はありません。

そのような互換タイプを割り当てるにはさまざまな方法があります。

変数宣言中に型を代入します

このステートメントは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;

このソリューションの利点は、fruitsfreshFruitsの両方がApple[] | Pear[]型になることです。

64
Sefe

おそらく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);
4
Joe Frambach

コメントで@peterによってリンクされていた github issue で述べたように、

const freshFruits = (fruits as (Apple | Pear)[]).filter((fruit: (Apple | Pear)) => !fruit.isDecayed);
2
shusson