JavaScriptでの型安党性フロヌずTypeScript

流血の䌁業でUI開発を扱っおいる人なら誰でも、おそらく「MicrosoftのTypeScript」を意味する「型付きJavaScript」に぀いお聞いたこずがあるでしょう。しかし、この゜リュヌションの他に、少なくずも1぀の䞀般的なJSタむピングシステムがあり、ITの䞖界の䞻芁なプレヌダヌからのものもありたす。これはFacebookからのフロヌです。マむクロ゜フトが個人的に嫌いなため、以前は垞にフロヌを䜿甚しおいたした。客芳的には、これは既存のナヌティリティずの良奜な統合ず移行の容易さによっお説明されたした。



残念ながら、2021幎には、人気ずさたざたなナヌティリティおよびラむブラリからのサポヌトの䞡方で、フロヌがTypeScriptよりも倧幅に劣っおいるこずを認めなければなりたせん。それを棚に埋めお、サボテンを噛むのを やめる時が来たした 。事実䞊のTypeScript暙準に移動したす。しかし、この䞋で、最埌にこれらのテクノロゞヌを比范したいず思いたす。たずえば、Facebookからのフロヌのカップルたたはカップルではないです。



JavaScriptで型安党性が必芁なのはなぜですか



JavaScriptは玠晎らしい蚀語です。いいえ、これは奜きではありたせん。 JavaScriptを䞭心に構築された゚コシステムは玠晎らしいです。 2021幎、圌女は蚀語の最新機胜を䜿甚できるずいう事実を本圓に賞賛し、ビルドシステムの1぀の蚭定を倉曎するこずで、IE8を含む叀いバヌゞョンのブラりザヌでの実行をサポヌトするために実行可胜ファむルをトランスパむルしたす。 、倜は芚えおいたせん。 「HTMLで曞く」JSXを意味するこずができ、ナヌティリティbabel



たたは tsc



を䜿甚しお、 すべおのタグを、Reactラむブラリたたは他の、ただし別の投皿で詳しく説明したすを呌び出すなどの正しいJavaScript構造に眮き換えたす。



JavaScriptがブラりザで実行されるスクリプト蚀語ずしお優れおいるのはなぜですか



  • JavaScriptを「コンパむル」する必芁はありたせん。 JavaScript構造を远加するだけで、ブラりザヌはそれらを理解する必芁がありたす。これはすぐに䟿利でほずんど無料のものをたくさん䞎えたす。たずえば、ブラりザで盎接デバッグするこずは、プログラマヌたずえば、コンパむラヌのデバッグオプションず察応するラむブラリの束を含めるこずを忘れおはなりたせんの責任ではなく、ブラりザヌの開発者の責任です。 10k行のプロゞェクトがコンパむルされおいる間、10〜30分C / C ++の堎合はリアルタむム埅぀必芁はありたせん。行を倉曎し、ブラりザペヌゞをリロヌドしお、コヌドの新しい動䜜を芳察するだけです。たた、たずえばwebpackを䜿甚しおいる堎合は、ペヌゞも再読み蟌みされたす。倚くのブラりザでは、devtoolsを䜿甚しおペヌゞ内でコヌドを倉曎できたす。
  • - . 2021 . Chrome/Firefox, , , 5% (enterprise-) 30% (UI/) , .
  • JavaScript , . — ( worker'). , 100% CPU ( UI ), , , Promise/async/await/etc.
  • 同時に、なぜJavaScriptが重芁なのかずいう質問すら考えおいたせん。結局のずころ、JSの助けを借りお、次のこずができたすフォヌムを怜蚌し、ペヌゞコンテンツを完党にリロヌドせずに曎新し、非暙準の動䜜効果を远加し、オヌディオずビデオを操䜜し、゚ンタヌプラむズアプリケヌションのクラむアント党䜓をJavaScript。


ほずんどすべおのスクリプトむンタプリタ蚀語ず同様に、JavaScriptでは...壊れたコヌドを曞くこずができたす。ブラりザがこのコヌドに到達しない堎合、゚ラヌメッセヌゞ、譊告、たたは䜕も衚瀺されたせん。䞀方では、これは良いこずです。倧芏暡で倧芏暡なWebサむトがある堎合、ボタンクリックハンドラヌのコヌドに構文゚ラヌがあっおも、ナヌザヌがサむトを完党にロヌドしないこずはありたせん。



しかし、もちろん、これは悪いこずです。サむトのどこかで䜕かが機胜しおいないずいう事実自䜓が悪いからです。そしお、コヌドが動䜜するサむトに到達する前に、サむト䞊のすべおのスクリプトをチェックしお、少なくずもコンパむルされおいるこずを確認するのは玠晎らしいこずです。そしお理想的には-そしお働く。このために、さたざたなナヌティリティのセットが䜿甚されたす私のお気に入りのセットは、npm + webpack + babel / tsc + karma + jsdom + mocha + chaiです。



私たちが理想的な䞖界に䜏んでいる堎合、サむト䞊のすべおのスクリプトは、1行のスクリプトであっおも、テストでカバヌされたす。しかし、残念ながら、䞖界は理想的ではなく、テストでカバヌされおいないコヌドのすべおの郚分に぀いお、私たちはある皮の自動化された怜蚌ツヌルにしか頌るこずができたせん。確認できるもの



  • JavaScript. , JavaScript, , , . /// .
  • . , , . , :



    var x = null;
    x.foo();
    
          
          





    . — null .


セマンティクス゚ラヌに加えお、さらにひどい゚ラヌ、぀たり論理゚ラヌが発生する可胜性がありたす。プログラムが゚ラヌなしで実行されたが、結果がたったく期埅されたものではない堎合。文字列ず数字が远加されたクラシック



console.log( input.value ) // 1
console.log( input.value + 1 ) // 11

      
      





既存の静的コヌド分析ツヌルeslintなどは、プログラマヌがコヌドで行う朜圚的な゚ラヌのかなりの数を远跡しようずする可胜性がありたす。䟋えば





これらのルヌルはすべお、本質的にリンタヌがプログラマヌに課す制玄であるこずに泚意しおください。぀たり、リンタヌは実際 にはJavaScript蚀語の機胜を䜎䞋させるため、プログラマヌは朜圚的なミスを枛らすこずができたす。 all-allルヌルを有効にするず、条件で割り圓おを行うこずは䞍可胜になりJavaScriptは最初はこれを蚱可したすが、オブゞェクトリテラルで重耇キヌを䜿甚し、呌び出すこずさえできたせん console.log()



。



倉数の型の远加ず呌び出しの型チェックは、朜圚的な゚ラヌを枛らすためのJavaScript蚀語の远加の制限です。



画像

数倀に文字列を掛けようずしおいたす



オブゞェクトの存圚しないタむプに蚘述されおいないプロパティにアクセスしようずしたした

オブゞェクトの存圚しない型に蚘述されおいないプロパティにアクセスしようずしたした。



オブゞェクトの存圚しないタむプに蚘述されおいないプロパティにアクセスしようずしたした

匕数の型が䞀臎しない関数を呌び出そうずしたした。



型チェッカヌなしでこのコヌドを蚘述した 堎合、コヌドは正垞にトランスパむルされたす。オブゞェクトのタむプに関する情報を明瀺的たたは暗黙的に䜿甚しない堎合、静的コヌド分析の手段はこれらの゚ラヌを芋぀けるこずができたせん。



぀たり、JavaScriptに入力を远加するず、プログラマヌが䜜成するコヌドに远加の制限が远加されたすが、スクリプトの実行䞭に぀たり、ナヌザヌのブラりザヌで発生する可胜性のある゚ラヌを芋぀けるこずができたす。



JavaScriptタむピング機胜



フロヌ TypeScript
倉数の型、匕数、たたは関数の戻り型を蚭定する機胜
a : number = 5;
function foo( bar : string) : void {
    /*...*/
} 

      
      



オブゞェクトタむプむンタヌフェむスを蚘述する機胜
type MyType {
    foo: string,
    bar: number
}

      
      



タむプの倀を制限する
type Suit = "Diamonds" | "Clubs" | "Hearts" | "Spades";

      
      



列挙甚の個別のタむプレベルの拡匵
enum Direction { Up, Down, Left, Right }

      
      



「远加」タむプ
type MyType = TypeA & TypeB;

      
      



耇雑なケヌスの远加の「タむプ」
$Keys<T>, $Values<T>, $ReadOnly<T>, $Exact<T>, $Diff<A, B>, $Rest<A, B>, $PropertyType<T, k>, $ElementType<T, K>, $NonMaybeType<T>, $ObjMap<T, F>, $ObjMapi<T, F>, $TupleMap<T, F>, $Call<F, T...>, Class<T>, $Shape<T>, $Exports<T>, $Supertype<T>, $Subtype<T>, Existential Type (*)
      
      



Partial<T>, Required<T>, Readonly<T>, Record<K,T>, Pick<T, K>, Omit<T, K>, Exclude<T, U>, Extract<T, U>, NonNullable<T>, Parameters<T>, ConstructorParameters<T>, ReturnType<T>, InstanceType<T>, ThisParameterType<T>, OmitThisParameter<T>, ThisType<T>

      
      





JavaScriptタむプをサポヌトするための䞡方の゚ンゞンは、ほが同じ機胜を備えおいたす。ただし、匷い型の蚀語を䜿甚しおいる堎合、型付きのJavaScriptでもJavaずは非垞に重芁な違いがありたす。すべおの型は基本的にむンタヌフェむス、぀たりプロパティのリストおよびその型や匕数を蚘述したす。たた、2぀のむンタヌフェむスが同じたたは互換性のあるプロパティを蚘述しおいる堎合は、それらを互いに代わりに䜿甚できたす。぀たり、次のコヌドは型付きJavaScriptでは正しいですが、JavaやC ++では明らかに正しくありたせん。



type MyTypeA = { foo: string; bar: number; }
type MyTypeB = { foo: string; }

function myFunction( arg : MyTypeB ) : string {
    return `Hello, ${arg.foo}!`;
}

const myVar : MyTypeA = { foo: "World", bar: 42 } as MyTypeA;
console.log( myFunction( myVar ) ); // "Hello, World!"

      
      





MyTypeBむンタヌフェむスにはfoo



型を 持぀プロパティが必芁string



ですが、MyTypeAむンタヌフェむスを持぀倉数には必芁なので、このコヌドは型付きJavaScriptの芳点からは正しい です。



このコヌドは、倉数のリテラルむンタヌフェむスを䜿甚しお、少し短く曞き盎すこずができ たす myVar



。



type MyTypeB = { foo: string; }

function myFunction( arg : MyTypeB ) : string {
    return `Hello, ${arg.foo}!`;
}

const myVar = { foo: "World", bar: 42 };
console.log( myFunction( myVar ) ); // "Hello, World!"

      
      





myVar



この䟋の倉数タむプ はリテラルむンタヌフェむス { foo: string, bar: number }



です。それでもarg



関数の 匕数の期埅されるむンタヌフェヌスず互換性があるmyFunction



ので、このコヌドは、たずえばTypeScriptの芳点から゚ラヌがありたせん 。



この動䜜により、さたざたなラむブラリ、カスタムコヌドを操䜜するずき、さらには関数を呌び出すずきの問題の数が倧幅に枛少したす。兞型的な䟋は、いく぀かのラむブラリが有効なオプションを定矩し、それらをオプションオブゞェクトずしお枡す堎合です。



// -  
interface OptionsType {
    optionA?: string;
    optionB?: number;
}
export function libFunction( arg: number, options = {} as OptionsType) { /*...*/ }

      
      





//   
import {libFunction} from "lib";
libFunction( 42, { optionA: "someValue" } );

      
      





タむプはOptionsType



ラむブラリから゚クスポヌトされないこずに泚意しおください カスタムコヌドにむンポヌトされるこずもありたせん。ただし、これにより、options



関数の2番目の匕数、および型指定システムにリテラルむンタヌフェむスを䜿甚しお関数を呌び出し、 この匕数の型の互換性を確認するこずができたす。Javaでこのようなこずをしようずするず、コンパむラ間で明らかに混乱が生じたす。



ブラりザの芳点からはどのように機胜したすか



MicrosoftのTypeScriptもFacebookのフロヌもブラりザでサポヌトされおいたせん。たた、最新のJavaScript蚀語拡匵機胜は、䞀郚のブラりザヌでただサポヌトされおいたせん。では、このコヌドは、たず、正確性をどのようにチェックし、次に、ブラりザヌによっおどのように実行されるのでしょうか。



答えはtraspilingです。すべおの「非暙準」JavaScriptコヌドは、「非暙準」ブラりザヌには䞍明コヌドをブラりザヌが理解できる䞀連の呜什に倉換する䞀連のナヌティリティを通過したす。そしお、タむピングの堎合、「倉換」党䜓は、すべおの型の改良、すべおのむンタヌフェヌス蚘述、コヌドからのすべおの制限が単に削陀されるずいう事実にありたす。たずえば、䞊蚘の䟋のコヌドは...になりたす。



/* : type MyTypeA = { foo: string; bar: number; } */
/* : type MyTypeB = { foo: string; } */

function myFunction( arg /* : : MyTypeB */ ) /* : : string */ {
    return `Hello, ${arg.foo}!`;
}

const myVar /* : : MyTypeA */ = { foo: "World", bar: 42 } /* : as MyTypeA */;
console.log( myFunction( myVar ) ); // "Hello, World!"

      
      





それら。

function myFunction( arg ) {
    return `Hello, ${arg.foo}!`;
}
const myVar = { foo: "World", bar: 42 };
console.log( myFunction( myVar ) ); // "Hello, World!"

      
      





この倉換は通垞、次のいずれかの方法で行われたす。



  • フロヌからタむプ情報を削陀するには、babelプラグむンを䜿甚したす@ babel / plugin-transform-flow-strip-types
  • 2぀の゜リュヌションのいずれかを䜿甚しおTypeScriptを操䜜できたす。たず、babelず@ babel / plugin-transform-typescriptプラグむンを䜿甚できたす
  • 次に、babelの代わりに、tscず呌ばれるMicrosoft独自のトランスパむラヌを䜿甚できたす。このナヌティリティは、 babelではなくアプリケヌションビルドプロセスに組み蟌たれおいたす。


フロヌおよびTypeScripttscを䜿甚のプロゞェクト蚭定の䟋。

フロヌ TypeScript
webpack.config.js
{
  test: /\.js$/,
  include: /src/,
  exclude: /node_modules/,
  loader: 'babel-loader',
},

      
      



{
  test: /\.(js|ts|tsx)$/,
  exclude: /node_modules/,
  include: /src/,
  loader: 'ts-loader',
},

      
      



トランスパむラヌ蚭定
babel.config.js tsconfig.json
module.exports = function( api ) {
  return {
    presets: [
      '@babel/preset-flow',
      '@babel/preset-env',
      '@babel/preset-react',
    ],
  };
};

      
      



{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": false,
    "jsx": "react",
    "lib": ["dom", "es5", "es6"],
    "module": "es2020",
    "moduleResolution": "node",
    "noImplicitAny": false,
    "outDir": "./dist/static",
    "target": "es6"
  },
  "include": ["src/**/*.ts*"],
  "exclude": ["node_modules", "**/*.spec.ts"]
}

      
      



.flowconfig
[ignore]
<PROJECT_ROOT>/dist/.*
<PROJECT_ROOT>/test/.*
[lints]
untyped-import=off
unclear-type=off
[options]

      
      





バベル+ストリップずtscのアプロヌチの違いは、組み立おの点ではわずかです。最初のケヌスでは、babelが䜿甚され、2番目のケヌスでは、tscになりたす。





ただし、eslintなどのナヌティリティを䜿甚する堎合は違いがありたす。eslintでリントするためのTypeScriptには、さらに倚くのバグを芋぀けるこずができる独自のプラグむンのセットがありたす。ただし、リンタヌによる分析時に、倉数のタむプに関する情報が含たれおいる必芁がありたす。これを行うには、コヌドパヌサヌずしおtscのみを䜿甚し、babelは䜿甚しないでください。しかし、リンタヌにtscを䜿甚する堎合、構築にbabelを䜿甚するのは誀りです䜿甚するナヌティリティの動物園は最小限に抑える必芁がありたす。





フロヌ TypeScript
.eslint.js
module.exports = {
  parser: 'babel-eslint',
  parserOptions: {
    /* ... */

      
      



module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    /* ... */

      
      





ラむブラリのタむプ



ラむブラリがnpmリポゞトリに公開されるず、公開されるのはJavaScriptバヌゞョンです。プロゞェクトで䜿甚するために、公開されたコヌドを倉曎する必芁はないず想定されおいたす。぀たり、コヌドはすでにbabelたたはtscを介しお必芁なtraspilationを通過しおいたす。しかし、コヌド内のタむプに関する情報はすでに倱われおいたす。䜕をすべきか



フロヌでは、「玔粋な」JavaScriptバヌゞョンに加えお、ラむブラリに拡匵子が付いたファむルが含たれるず想定されおいたす。 .js.flow



すべおのタむプ定矩を含む゜ヌスフロヌコヌドが含たれおいたす。次に、フロヌを分析するずきに、これらのファむルを接続しお型チェックを行うこずができたす。プロゞェクトのビルドずその実行時には、これらのファむルは無芖されたす。通垞のJSファむルが䜿甚されたす。簡単なコピヌで.flowファむルをラむブラリに远加できたす。ただし、これにより、npmでのラむブラリのサむズが倧幅に増加したす。



TypeScriptでは、゜ヌスファむルを䞊べお保持するこずはお勧めしたせんが、定矩のリストのみを保持するこずをお勧めしたす。ファむルがある堎合 myModule.js



、プロゞェクトを分析するずきに、TypeScriptは近くのファむルを探したす。このファむルには myModule.js.d.ts



、すべおのタむプ、関数、およびタむプの分析に必芁なその他のものの定矩コヌドではありたせんが衚瀺されたす。tscトランスパむラヌは、゜ヌスTypeScriptからそのようなファむルを独自に䜜成できたすオプションを参照 declaration



ドキュメント内。



レガシヌラむブラリのタむプ



フロヌずTypeScriptの䞡方で、最初にこれらの説明が含たれおいないラむブラリの型宣蚀を远加する方法がありたす。しかし、それはさたざたな方法で行われたす。



フロヌに぀いおは、Facebook自䜓がサポヌトする「ネむティブ」な方法はありたせん。しかし、そのような定矩をリポゞトリに収集するフロヌ型のプロゞェクト がありたす。実際、npmがそのような定矩をバヌゞョン管理するための䞊列方法であり、曎新の非垞に䟿利な「集䞭型」方法でもありたせん。



TypeScriptでは、このような定矩を蚘述する暙準的な方法は、「@ types」プレフィックスが付いた特別なnpmパッケヌゞでそれらを公開するこず です。..。ラむブラリのタむプの説明をプロゞェクトに远加するには、察応する@ types-libraryを接続するだけで十分です。たずえば、 @types/react



Reactや @types/chai



chaiなどです。



フロヌずTypeScriptの比范



フロヌずTypeScriptを比范する詊み。遞択された事実は、NathanSebhastianの蚘事「TypeScriptVSFlow」から収集され、䞀郚は独立しお収集されたす。



さたざたなフレヌムワヌクにわたるネむティブサポヌト。ネむティブ-はんだごおずサヌドパヌティのラむブラリおよびプラグむンを䜿甚した远加のアプロヌチはありたせん。



様々な支配者

フロヌ TypeScript
䞻な貢献者 フェむスブック マむクロ゜フト
りェブサむト flow.org www.typescriptlang.org
Github github.com/facebook/flow github.com/microsoft/TypeScript
GitHubが開始したす 21.3k 70.1k
GitHubフォヌク 1.8k 9.2k
GitHubの問題オヌプン/クロヌズ 2.4k / 4.1k 4.9k / 25.0k
StackOverflowアクティブ 2289 146,221
StackOverflow頻繁 123 11451


これらの数字を芋るず、私にはフロヌの䜿甚を掚奚する道埳的暩利がありたせん。しかし、なぜ私はそれを自分で䜿甚したのですか以前はフロヌランタむムなどがあったからです。



フロヌランタむム



flow-runtimeは、フロヌタむプをランタむムに埋め蟌み、実行時に倉数タむプを定矩するために䜿甚できる、そしお最も重芁なこずずしお、実行時に倉数のタむプをチェックできるようにする、babelのプラグむンのセットです。これにより、実行時に、たずえば自動テストや手動テスト䞭に、アプリケヌションの远加のバグをキャッチできたす。



぀たり、実行時にもちろん、デバッグアセンブリで、アプリケヌションは、すべおのタむプの倉数、匕数、サヌドパヌティ関数の呌び出しの結果、およびすべお、すべお、すべおを明瀺的にチェックしお、それらのタむプに準拠しおいるかどうかを確認したした。



残念ながら、2021幎の新幎には、リポゞトリの䜜成者が 情報を远加したした圌はもはやこのプロゞェクトの開発に関䞎しおおらず、通垞はTypeScriptに切り替えおいたす。実際、流れを維持する最埌の理由は私にずっお非掚奚になりたした。さお、TypeScriptぞようこそ。



All Articles