web-dev-qa-db-ja.com

Flowに値を別の型にキャストさせるにはどうすればよいですか?

Flow で変数を強制的にキャストすることは可能ですか?

type StringOrNumber = string | number
const foo: StringOrNumber = 'hello'

// I look for something like `const bar:string = (string) foo`
const bar: string = foo // fails
const bar: string = (foo: string) // also fails
28
czerny

フローは、あるタイプから別のタイプへの直接キャストを行いませんが、次のようなことができます

const bar: string = (foo: any);

fooは任意のタイプの値を入力として受け入れるため、anyanyにキャストします。その後、any型でもすべての可能な型を読み取ることができるため、anybarでもあるため、anyの値をstringに割り当てることができます。

40
loganfsmyth

この例では、ユニオン型からそのメンバーの1つへの「キャスト」を見ています。これはキャストと考えるのが一般的ですが、他の言語での型キャストとは異なります。

fooのタイプをstring | numberに設定することで、この値が文字列または数値のいずれかになる可能性があることをFlowに伝えました。その後、たまたま文字列を挿入しますが、Flowはそのタイプに関する直接のアサーションを破棄しません。これは、後で変更できない状況(このような)でもです。

それをstring型の変数に割り当てるには、Flowは、stringまたはnumberのいずれかであったとしても、割り当てを行うまでに、stringのみであることを確認する必要があります。

可能なオプションを減らすこのプロセスは、typerefinementと呼ばれます。

タイプの改良

タイプを改良するには、それが私たちが言っているタイプでなければならないことを証明する必要がありますフローが理解する方法で

元の例では、typeofを使用してこれを行うことができます。

type StringOrNumber = string | number
const foo: StringOrNumber = 'hello'

// This would raise an error here:
// const bar: string = foo

if (typeof foo === "string") {
  // Flow now knows that foo must be a string, and allows this.
  const bar: string = foo
}

人間が型の改良として見ることができるものすべてがFlowによって理解されるわけではないので、Flowで何が理解されるのかを確認するために、 refinement docs を見る必要がある場合があります。

抑制コメント

Flowの改良の安全性を表現する方法がない場合があります。 抑制コメント を使用して、Flowにステートメントを強制的に受け入れさせることができます。そうしないと、Flowが報告するエラーが抑制されます。デフォルトの抑制コメントは$FlowFixMeですが、別のコメントに設定することができます。

フローは、この2行目にエラーを報告し、unionValueのタイプが「number」であることを報告します。

const unionValue: StringOrNumber = 'seven'
const stringValue: string = unionValue

ただし、抑制コメントを使用することにより、フローに合格します。

const unionValue: StringOrNumber = 'seven'
// $FlowFixMe: We can plainly see this is a string!
const stringValue: string = unionValue

抑制コメントの便利な機能の1つは、抑制エラーを伴わない抑制コメントはエラーと見なされることです。例でタイプを変更した場合:

const unionValue: string = 'seven'
// $FlowFixMe: Even though this is a string, suppress it
const stringValue: string = unionValue

これで、Flowは代わりに「未使用の抑制」エラーを報告し、警告を出します。これは、Flowが絞り込みを認識できるはずだが、できない場合に特に便利です-抑制コメントを使用することで、Flowの将来のバージョンがコードをタイプセーフ。

キャストスルー-すべて

フローの安全性を示す方法で本当に表現できず、抑制コメントを使用できない(または使用しない)場合は、任意の型をanyにキャストし、anyを任意の型にキャストできます。

const unionValue: StringOrNumber = 'seven'
// Flow will be okay with this:
const stringValue: string = (unionValue: any)

値をanyにキャストすることで、Flowに値の型について知っていることをすべて忘れて、それに対して行うことはすべて正しいと仮定します。後で型付き変数に入れた場合、Flowはそれが正しいと仮定します。

ご注意

抑制コメントとキャストスルーanyの両方がnsafeであることに注意することが重要です。 Flowを完全にオーバーライドし、完全に無意味な「キャスト」を喜んで実行します。

const notAString: {key: string, key2: number} = {key: 'value', key2: 123}
// This isn't right, but Flow won't complain:
const stringValue: string = (notAString: any)

この例では、stringValueobjectnotAStringを保持していますが、Flowはそれが文字列であることを確認しています。

これを回避するために、フローが理解できる改良を可能な限り使用し、他の安全でない「キャスト」技術の使用を避けます。

17
Jason Wodicka

この答えは単なる提案です。イベントおよびHTMLElementに関連する型チェックの問題のソリューションを参照するとき、instanceofを呼び出す多くのガードに遭遇しました。

型チェックを満足させるために、この汎用ガードを導入し、cast(もちろんキャストになりません)と呼びました。

もちろん、コストはパフォーマンスに影響します(ゲームを作成する場合はかなり関連がありますが、ほとんどのユースケースでは、反復あたりのミリ秒よりもタイプガードの方がメリットがあると思います)。

const cast = (type : any, target : any) => {
    if (!(target instanceof type)) {
        throw new Error(`${target} is not a ${type}`);
    }
    return target;
}

使用法:

const fooLayer = cast(HTMLCanvasElement, document.getElementById("foo-layer"));
window.addEventListener("click", (ev : Event) =>
  console.log(cast(MouseEvent, ev).clientX - cast(HTMLElement, ev.target).offsetLeft,
    cast(MouseEvent, ev).clientY - cast(HTMLElement, ev.target).offsetTop));
1
renevanderark