2017-02-15 22 views
1

私は誰かが私の下のタイプで見つからないものを識別するのを助けることを望んでいます。 matchという関数を作成しました。この関数は、特定されたときに一致する関数を実行するタプル の配列をとります。たとえば:Flowtypeの統一タイプを防ぐにはどうすればいいですか?

type Fn1<A, B> = (a: A, ...rest: empty[]) => B; 
 
declare export function match<A>(
 
    xs: Array<[Class<A>, (x: A) => mixed]>, 
 
    ...rest: empty[] 
 
): Fn1<A, mixed>; 
 

 
describe('match',() => { 
 
    class FileExists {} 
 
    class FileDoesNotExist {} 
 
    let matcher: (x: FileExists | FileDoesNotExist) => mixed; 
 

 
    beforeEach(() => { 
 
     const whenFileExists = [FileExists, (x: FileExists) => x]; 
 
     const whenFileDoesNotExist = [FileDoesNotExist, (x: FileDoesNotExist) => x]; 
 
     matcher = match([whenFileExists, whenFileDoesNotExist]); 
 
    }); 
 

 
    it('should return an instance of whenFileDoesNotExist',() => { 
 
     // Should invoke the function in the tuple containing the FileDoesNotExist class 
 
     expect(matcher(new FileDoesNotExist()) instanceof FileDoesNotExist).toBe(true); 
 
    }); 
 
});

問題は種類が統一されていることのようです。私は次のエラーを取得しています:

`` `

1406:みましょうマッチャー:(X:FILEEXISTS | FileDoesNotExist)=>混合します; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileDoesNotExist。このタイプは、予想されるパラメータタイプ 1409と互換性がありません:const whenFileExists = [FileExists、(x:FileExists)=> x]; ^^^^^^^^^^ FILEEXISTS

テスト/ fp.test.js:1406 1406:せマッチャ:(X:FILEEXISTS | FileDoesNotExist)=>混合。 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileExists。 (X:FileDoesNotExist)=> X ^^^^^^^^^^^^^^^^ FileDoesNotExist

テスト/ fp.test.jsこのタイプ 1412予想PARAMタイプと互換性がありません:1409 1409:const whenFileExists = [FileExists、(x:FileExists)=> x]; ^^^^^^^^^ FileExists。 (X:FileDoesNotExist)=> X ^^^^^^^^^^^^^^^^ FileDoesNotExist

テスト/ fp.test.jsこのタイプ 1412予想PARAMタイプと互換性がありません:1409 1409:const whenFileExists = [FileExists、(x:FileExists)=> x]; ^ FileExists。 (X:FileDoesNotExist)=> X ^^^^^^^^^^^^^^^^ FileDoesNotExist

テスト/ fp.test.jsこのタイプ 1412予想PARAMタイプと互換性がありません:1411 1411:FileDoesNotExist、 ^^^^^^^^^^^^^^^^ FileDoesNotExist。このタイプは、予想されるパラメータタイプ 1409と互換性がありません:const whenFileExists = [FileExists、(x:FileExists)=> x]; ^^^^^^^^^^ FILEEXISTS

テスト/ fp.test.js:1412 1412:(X:FileDoesNotExist)=> X ^ FileDoesNotExist。このタイプは、予想されるパラメータタイプ 1409と互換性がありません:const whenFileExists = [FileExists、(x:FileExists)=> x]; ^^^^^^^^^^ FILEEXISTS

`` `

私はここに欠けているかを把握することはできません。誰かが私が外に出ているか忘れている何かを見ますか?

答えて

0

タイプ変数Aは、match内で使用されるどこでも同じタイプに解決されなければならず、それが原因です。

パラメータを削除して、Flowが実行しようとしていることを試みると、同じ問題が発生します。

type Existence = FileExists | FileDoesNotExist 

declare export function match(
    xs: Array<[Class<Existence>, (x: Existence) => mixed]>, 
    ...rest: empty[] 
): Fn1<Existence, mixed>; 

しかし Existenceはクラスではないので、 Class<Existence>はどんな意味がないので、これは動作しません:あなたは(私は Existenceを呼び出しします)タイプ Aは、最も一般的なケースになりたいです。

Class<A>Aは配列の要素ごとに異なる必要がありますが、これは不可能です。代わりに、*と表示される存在タイプを使用できます。あなたは正確にそれ以外の場合は、それを表現することができないにもかかわらず、フローが正しく、実際の型を推論することができます:ここで

declare export function match<A>(
    xs: Array<[Class<*>, (x: A) => mixed]>, 
    ...rest: empty[] 
): Fn1<*, mixed>; 

を、AFileExists | FileDoesNotExistとして解決されますが、*が使用されているそれぞれの場所では、それだけであることを推測することができます使用方法によってはFileExistsまたはFileDoesNotExistのいずれかです。

これは、this blogpostとは別にどこにも記載されていないため、そのセマンティクスについては100%確信していません。使い方を正確にするにはちょっとした手間がかかります。

+0

こんにちはPeterさん、詳細な応答をいただきありがとうございます。実在型は、フローが使用されている実際の型を推測できるように見える。これは、私が見ているエラーを削除しますが、残念ながら、私は意図的に追加するエラーをキャッチすることはできません。たとえば、私が[FileExists、(x:{id:number})=> x]のようにしたとします。上記の場合、 'x'はオブジェクトではなくFileExistsのインスタンスでなければならないので、エラーが発生すると思います。しかし、流れはこれを拾うようには見えません。 –

+0

さて、それは迷惑です。私が考えることができる唯一の他の解決策(あなたが望むものではないかもしれない)は、 'FileExists'と' FileDoesNotExist'の共通基底クラスを作ることです。次に、ラムダの引数型として基本クラスを使用できます。 '*'型を取り除いて、 'A'型のパラメータを元の場所に戻すこともできます。 –

+0

Peterの説明にもう一度感謝します。私たちはこの作業を行う方法を考え出しましたが、それは最も理想的ではありません(上記の記事を参照)。興味がある場合は、Flowtype githubページで問題を作成しました:https://github.com/facebook/flow/issues/3393 –

0

実在のタイプは素晴らしいアイデアでしたが、問題はそれが必要なときにエラーを捕捉しないことです。例えば、私がしなければ、次の

declare export function match<A>(
    xs: Array<[Class<*>, (x: A) => mixed]>, 
    ...rest: empty[] 
): Fn1<*, mixed>; 

const whenFileExists = [FileExists, (x: FileExists) => x]; 
const whenFileDoesNotExist = [FileDoesNotExist, (x: string) => x]; 
matcher = fp.match([whenFileExists, whenFileDoesNotExist]); 
(matcher(new FileDoesNotExist()): mixed); 

は、我々はそれがFileDoesNotExistのインスタンスでなければなりませんので、xstringとして指定されたエラーを取得する必要があります。ただし、フローではこのエラーは発生しません。それぞれのケースで宣言を追加するという代償を払って、この作業を行う方法があることが判明しました。これは、2つの項目がある場合の宣言と、3つの項目がある場合のための別個の宣言を意味します。宣言はnエントリのために行われる必要があります:それは、それぞれの場合の宣言を書き出すための痛みですが

declare export function match<A, B>(
    xs: [[Class<A>, (x: A) => mixed], [Class<B>, (x: B) => mixed]], 
    ...rest: empty[] 
): (x: A | B) => mixed; 

declare export function match<A, B, C>(
    xs: [[Class<A>, (x: A) => mixed], [Class<B>, (x: B) => mixed], [Class<C>, (x: C) => mixed]], 
    ...rest: empty[] 
): (x: A | B | C) => mixed; 

、ほとんどの場合、上の一致する5つの以上のアイテムを持っていることはほとんどありません。私は安全に最大5つのエントリの宣言を追加することができるはずです。上記のスニペットに行く、これは文字列としてのxをキャッチし、次のエラーがスローされます。

This type is incompatible with the expected param type of string: test.js:xx

フローは実存タイプを使用して、これを推測することができるならばそれはいいだろう。

関連する問題