Miért érdemes statikus típusokat használni a JavaScriptben? (4 részes alapozó statikus gépeléshez Flow segítségével)

JavaScript-fejlesztőként egész nap kódolhat anélkül, hogy bármilyen statikus típust tapasztalna. Tehát miért bajlódni velük?

Nos, kiderült, hogy a tanulási típusok nem csak a tudatbővítés gyakorlása. Ha hajlandó egy kis időt fordítani a statikus típusok előnyeinek, hátrányainak és használati eseteinek megismerésére, az óriási segítséget jelenthet a programozásában.

Érdekelt? Nos, szerencséd van - erről szól a négyrészes sorozat többi része.

Először is, egy meghatározás

A statikus típusok megértésének leggyorsabb módja a dinamikus típusokkal való szembeállítás. A statikus típusú nyelvre statikusan tipizált nyelvként hivatkozunk . Másrészt a dinamikus típusú nyelveket dinamikusan tipizált nyelvnek nevezik .

Az alapvető különbség az, hogy a statikusan tipizált nyelvek a fordítás idején , míg a dinamikusan tipizált nyelvek futás közben ellenőrzik a típusellenőrzést .

Ez még egy koncepciót hagy maga után: mit jelent a „ típusellenőrzés” ?

Magyarázatként nézzük meg a Java és a Javascript típusait.

A „Típusok” a meghatározandó adatok típusára utal.

Például a Java-ban, ha az alábbiakat definiálja boolean:

boolean result = true;

Ennek megfelelő típusa van, mert a booleankommentár megegyezik a megadott értékkel result, szemben egy egész számmal vagy bármi mással.

Másrészt, ha megpróbálta kijelenteni:

boolean result = 123;

... ezt nem lehet összeállítani, mert helytelen típusa van. Kifejezetten a- resultként jelöl boolean, de ezután egész számként definiálja 123.

A JavaScript és más, dinamikusan beírt nyelvek eltérő megközelítést alkalmaznak, lehetővé téve a kontextus számára, hogy milyen típusú adatokat definiáljon:

var result = true;

Hosszú történet: a statikusan beírt nyelvek használatához meg kell adnia a konstrukció adattípusait. A dinamikusan beírt nyelvek nem. A JavaScript az adattípust jelenti, míg a Java egyenesen.

Tehát, amint láthatja, a típusok lehetővé teszik a program invariánsainak , illetve azoknak a logikai állításoknak és feltételeknek a megadását , amelyek mellett a program végrehajtásra kerül.

A típusellenőrzés ellenőrzi és kikényszeríti, hogy a konstrukció típusa (konstans, logikai érték, szám, változó, tömb, objektum) egyezik-e egy megadott invariánssal. Megadhatja például, hogy „ez a függvény mindig karakterláncot ad vissza”. Amikor a program fut, nyugodtan feltételezheti, hogy stringet ad vissza.

A statikus típusellenőrzés és a dinamikus típusellenőrzés közötti különbségek leginkább akkor számítanak, ha típushiba lép fel. Statikusan tipizált nyelvben típushibák fordulnak elő a fordítási lépés során, vagyis a fordítás idején. Dinamikusan beírt nyelvekben a hibák csak a program végrehajtása után jelentkeznek. Vagyis futás közben .

Ez azt jelenti, hogy egy dinamikusan beírt nyelven (például JavaScript vagy Python) írt program akkor is fordíthat, ha olyan típusú hibákat tartalmaz, amelyek egyébként megakadályoznák a parancsfájl megfelelő futtatását.

Másrészt, ha egy statikusan beírt nyelven (például Scala vagy C ++) írt program típushibákat tartalmaz, akkor a fordítás addig nem sikerül, amíg a hibákat nem javítják.

A JavaScript új korszaka

Mivel a JavaScript dinamikusan beírt nyelv, a változók, függvények, objektumok és bármi más deklarálásával el lehet menni anélkül, hogy megadná a típust.

Kényelmes, de nem mindig ideális. Éppen ezért a közelmúltban olyan eszközök léptek be, mint a Flow és a TypeScript, hogy a JavaScript fejlesztőknek * opciót * adjanak statikus típusok használatára.

A Flow egy nyílt forráskódú statikus típusellenőrző könyvtár, amelyet a Facebook fejlesztett ki és adott ki, és amely lehetővé teszi a típusok fokozatos hozzáadását a JavaScript-kódhoz.

A TypeScript viszont egy szuperhalmaz , amely lefordul a JavaScript-ig - bár úgy érzi magát, mint egy új, statikusan tipizált nyelvet. Ennek ellenére nagyon hasonlít a JavaScriptre, és nem nehéz felvenni.

Mindkét esetben, amikor típusokat szeretne használni, kifejezetten meg kell mondania az eszköznek, hogy mely fájlokat kell ellenőriznie. A TypeScript esetében ezt úgy kell megtenni, hogy a .tskiterjesztésű fájlokat írja a helyett .js. A Flow esetében megjegyzést fűz a fájl tetejéhez a@flow

Miután kijelentette, hogy egy fájlt szeretne ellenőrizni, akkor a megfelelő szintaxist kell használnia a típusok meghatározásához. A két eszköz között meg kell különböztetni, hogy a Flow típusú „ellenőrző” és nem fordító. A TypeScript viszont fordító.

Őszintén hiszem, hogy az olyan eszközök, mint a Flow és a TypeScript generációs váltást és előrelépést jelentenek a JavaScript számára.

Személy szerint annyit tanultam, hogy a mindennapokban használtam típusokat. Ezért remélem, hogy csatlakozol hozzám ezen a rövid és édes úton a statikus típusok felé.

A 4 részes bejegyzés további része a következőket tartalmazza:

I. rész: Gyors bevezető a Flow szintaxisához és nyelvéhez

II. És III. Rész A statikus típusok előnyei és hátrányai (részletes áttekintési példákkal)

IV. Rész Statikus típusokat használjon a JavaScript-ben vagy sem?

Ne feledje, hogy a Flow over TypeScript-et választottam a bejegyzésben szereplő példákban, mert jól ismerem. Saját céljaira végezzen kutatást, és válassza ki a megfelelő eszközt. A TypeScript is fantasztikus.

Minden további nélkül kezdjük!

1. rész: Gyors bevezető a Flow szintaxisához és nyelvéhez

A statikus típusok előnyeinek és hátrányainak megértéséhez először meg kell ismernie a statikus típusok szintaxisát a Flow segítségével. Ha még soha nem dolgozott statikusan tipizált nyelven, a szintaxis eltarthat egy ideig, amíg megszokja.

Kezdjük azzal, hogy megvizsgáljuk, hogyan adhatunk típusokat a JavaScript primitívekhez, valamint olyan konstrukciókhoz, mint a tömbök, az objektumok, a függvények stb.

logikai érték

Ez egy boolean(igaz vagy hamis) értéket ír le a JavaScript-ben.

Vegye figyelembe, hogy amikor meg akar adni egy típust, a használt szintaxis a következő:

szám

Ez egy IEEE 754 lebegőpontos számot ír le. Sok más programozási nyelvtől eltérően a JavaScript nem határoz meg különböző típusú számokat (például egész számokat, rövid, hosszú és lebegő pontokat). Ehelyett a számokat mindig kettős pontosságú lebegőpontos számként tárolják. Ezért bármilyen szám meghatározásához csak egy számtípusra van szükség.

numbertartalmazza Infinityés NaN.

húr

Ez egy karakterláncot ír le.

nulla

Ez nulla JavaScript adattípusát írja le.

üres

Ez undefineda JavaScript adattípusát írja le.

Vegye figyelembe, hogy nullés undefinedmásként kezelik őket. Ha megpróbálta:

Az áramlás hibát vethet fel, mert a típus voidfeltételezhetően olyan típusú, undefinedamely nem azonos a típussal null.

Sor

Leír egy JavaScript tömböt. A Array<T> szintaxist egy tömb leírására használja, amelynek elemei valamilyen T típusúak.

Figyelje meg, hogyan helyettesítettem Ta következővel string: ez azt jelenti, hogy messagesstringek tömbjeként deklarálom .

Tárgy

Ez egy JavaScript objektumot ír le. Néhányféle módon lehet típusokat hozzáadni az objektumokhoz.

Típusokat adhat az objektum alakjának leírására:

Az objektumokat térképként definiálhatja, ahol egy karakterláncot valamilyen értékhez rendel:

Az objektumot Objecttípusként is meghatározhatja :

Ez az utolsó megközelítés lehetővé teszi számunkra, hogy korlátozás nélkül állítsunk be bármilyen kulcsot és értéket az objektumon, így a típusellenőrzés szempontjából valójában nem jelent nagy értéket.

Bármi

Ez szó szerint bármilyen típust képviselhet. A anytípus gyakorlatilag nincs bejelölve, ezért próbálja elkerülni a használatát, hacsak nem feltétlenül szükséges (például amikor le kell tiltania a típusellenőrzést vagy szükség van egy menekülési nyílásra).

Az egyik olyan helyzet, amelyre anyhasznos lehet, egy olyan külső könyvtár használata, amely kiterjeszti egy másik rendszer prototípusait (például Object.prototype).

Például, ha olyan könyvtárat használ, amely kiterjeszti az Object.prototype doSomethingtulajdonságot:

Hibaüzenetet kaphat:

Ennek megkerüléséhez használhatja any:

Funkciók

A függvényekhez típusok hozzáadásának leggyakoribb módja az, hogy típusokat ad hozzá a bemeneti argumentumokhoz és (ha releváns) a visszatérési értékhez:

Akár típusokat is hozzáadhat az aszinkron függvényekhez (lásd alább) és a generátorokhoz:

Figyelje meg, hogy a második paraméterünket hogyan getPurchaseLimitjegyzik fel olyan függvényként, amely a-t adja vissza Promise. És fel amountExceedsPurchaseLimitvan tüntetve, mint visszatérő a Promise.

Írja be az álnevet

A típusaliasítás az egyik kedvenc módszerem a statikus típusok használatára. Lehetővé teszik a meglévő típusok (szám, karakterlánc stb.) Használatát új típusok összeállításához:

Fent, hoztam létre egy új típusú úgynevezett PaymentMethodamely olyan tulajdonságokkal, hogy állnak numberés stringtípusok.

Most, ha használni szeretné a PaymentMethodtípust, megteheti:

Típusaliasokat is létrehozhat bármely primitív számára, ha az alapul szolgáló típust egy másik típusba tekeri. Például, ha be akarja írni az alias a Nameés EmailAddress:

Ezzel jelzi ezt, Nameés Emailkülönálló dolgok, nem csak húrok. Mivel egy név és e-mail nem igazán cserélhető egymással, ez megakadályozza, hogy véletlenül összekeverje őket.

Generikusok

A generikus módszerek maguknak a típusoknak az elvonatkoztatására szolgálnak. Mit is jelent ez?

Lássuk:

Létrehoztam egy absztrakciót a típushoz T. Most bármilyen típust használhat, amelyet képviselni szeretne T. Mert numberT, Tvolt típusú number. Eközben ugyanis arrayTT típusú voltArray er>.

Yes, I know. It’s dizzying stuff if this is the first time you’re looking at types. I promise the “gentle” intro is almost over!

Maybe

Maybe type allows us to type annotate a potentially null or undefined value. They have the type T|void|null for some type T, meaning it is either type T or it is undefined or null. To define a maybe type, you put a question mark in front of the type definition:

Here I’m saying that message is either a string, or it’s null or undefined.

You can also use maybe to indicate that an object property will be either of some type T or undefined:

By putting the ? next to the property name for middleInitial, you can indicate that this field is optional.

Disjoint unions

This is another powerful way to model data. Disjoint unions are useful when you have a program that needs to deal with different kinds of data all at once. In other words, the shape of the data can be different based on the situation.

Extending on the PaymentMethod type from our earlier generics example, let’s say that you have an app where users can have one of three types of payment methods. In this case, you can do something like:

Then you can define your PaymentMethod type as a disjoint union with three cases.

Payment method now can only ever be one of these three shapes. The property type is the property that makes the union type “disjoint”.

You’ll see more practical examples of disjoint union types later in part II.

All right, almost done. There are a couple other features of Flow worth mentioning before concluding this intro:

1) Type inference: Flow uses type inference where possible. Type inference kicks in when the type checker can automatically deduce the data type of an expression. This helps avoid excessive annotation.

For example, you can write:

Even though this Class doesn’t have types, Flow can adequately type check it:

Here I’ve tried to define area as a string, but in the Rectangle class definition we defined width and height as numbers. So based on the function definition for area, it must be return a number. Even though I didn’t explicitly define types for the area function, Flow caught the error.

One thing to note is that the Flow maintainers recommend that if you were exporting this class definition, you’d want to add explicit type definitions to make it easier to find the cause of errors when the class is not used in a local context.

2) Dynamic type tests: What this basically means is that Flow has logic to determine what the the type of a value will be at runtime and so is able to use that knowledge when performing static analysis. They become useful in situations like when Flow throws an error but you need to convince flow that what you’re doing is right.

I won’t go into too much detail because it’s more of an advanced feature that I hope to write about separately, but if you want to learn more, it’s worth reading through the docs.

We’re done with syntax

We covered a lot of ground in one section! I hope this high-level overview has been helpful and manageable. If you’re curious to go deeper, I encourage you to dive into the well-written docs and explore.

With syntax out of the way, let’s finally get to the fun part: exploring the advantages and disadvantages of using types!

Next up: Part 2 & 3.