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
フローは、あるタイプから別のタイプへの直接キャストを行いませんが、次のようなことができます
const bar: string = (foo: any);
foo
は任意のタイプの値を入力として受け入れるため、any
をany
にキャストします。その後、any
型でもすべての可能な型を読み取ることができるため、any
はbar
でもあるため、any
の値をstring
に割り当てることができます。
この例では、ユニオン型からそのメンバーの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)
この例では、stringValue
はobject
のnotAString
を保持していますが、Flowはそれが文字列であることを確認しています。
これを回避するために、フローが理解できる改良を可能な限り使用し、他の安全でない「キャスト」技術の使用を避けます。
この答えは単なる提案です。イベントおよび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));