Vysvetlené typy strojopisu - mentálny model, ktorý vám pomôže premýšľať nad typmi

Blog

Vysvetlené typy strojopisu - mentálny model, ktorý vám pomôže premýšľať nad typmi

Jedného dňa som na to prišiel tweetovať od Lari Mazza:

Ako softvérový inžinier, ktorý sa najskôr naučil Python, Ruby, Javascript a Clojure, keď som vyskúšal C ++, to bol horor. Nemohol som veľa urobiť a bolo to také kontraproduktívne a frustrujúce. Možno preto, že som robil všetko zle a nerozumel som typom správnym spôsobom.

Ale aj keď som mal toľko problémov, dokázal som toho veľa implementovať algoritmy a dátové štruktúry .

Teraz, keď vo svojej každodennej práci používam stále viac a viac strojopisu moje vedľajšie projekty „Mám pocit, že som viac pripravený konfrontovať typy. Vlastne nie konfrontovať, ale použiť ich v môj prospech.

Tento príspevok je mojou snahou pomôcť vývojárom viac premýšľať v typoch a porozumieť tomuto mentálnemu modelu.

Myslenie v typoch JavaScript

Ak ste tu, pravdepodobne ste počuli, že Strojopis je nadmnožinou jazyka Javascript. Ak nie, skvelé, práve ste sa dnes dozvedeli niečo nové. JÉJ!

Strojopis je nadmnožina, pretože akýkoľvek kód Javascript je v strojopisu platný, syntakticky. V závislosti od konfigurácie kompilátora Typescript sa môže, ale nemusí kompilovať. Ale pokiaľ ide o syntax, funguje to dobre.

Z tohto dôvodu môžete Javascript migrovať do strojopisu postupne tak, že nahradíte | _+_ | rozšírenie s | _+_ |. Všetko bude bez typových vyhlásení (typ | _+_ |), ale to je iný príbeh.

Tiež, ak kódujete v Javascripte - alebo v inom programovacom jazyku - pravdepodobne uvažujete v typoch:

  • Hm, toto je zoznam celých čísel, takže budem musieť filtrovať iba párne čísla a vrátiť nový zoznam
  • Toto je objekt, ale potrebujem získať túto hodnotu reťazca z vlastnosti X
  • Táto funkcia prijíma dva parametre. A aj B sú celé čísla a chcem ich zhrnúť

Áno, rozumieš. Myslíme typovo. Ale sú len v našich hlavách. Neustále na nich myslíme, pretože potrebujeme vedieť narábať s údajmi, analyzovať ich alebo upravovať. Musíme vedieť, ktoré metódy môžeme v tomto type objektu používať.

Na konkrétnejšom príklade si predstavte, že chcete sčítať cenu všetkých produktov. Objekt produktu vyzerá takto:

.js

Teraz však so zoznamom produktov:

.ts

Dobre! Teraz chceme funkciu, ktorá zhrnie ceny všetkých produktov.

any

Jednoducho prijmite výrobky ako argument a znížte všetky ceny produktov. Javascript funguje dobre. Pri vytváraní tejto funkcie však začnete premýšľať o dátach a o tom, ako s nimi správne zaobchádzať.

Prvá časť: výrobky ako argument. Tu si len myslíte: Dostávame zoznam niektorých objektov. Áno, v našich hlavách sú produkty zoznamom. Preto môžeme uvažovať o použití | _+_ | metóda. Je to metóda z | _+_ | prototyp.

Potom si môžeme detailne premyslieť predmet. Vieme, že objekt produktu má | _+_ | nehnuteľnosť. A táto vlastnosť je číslo. Preto môžeme robiť | _+_ | a súčet s akumulátorom.

Rekapitulácia:

  • | _+_ | je zoznam predmetov.
  • Ako zoznam môžeme použiť | _+_ | metóda, pretože táto metóda je členom | _+_ | prototyp.
  • | _+_ | objekt má niektoré vlastnosti. Jedným z nich je | _+_ |, čo je číslo.
  • Ako číselnú vlastnosť ho môžeme použiť na súčet s redukčným akumulátorom.
  • Chceli sme vrátiť číslo, súčet cien všetkých produktov.

Vždy myslíme na dátové typy, stačí pridať anotácie typov, aby boli jasnejšie a požiadať kompilátora o pomoc. Naša pamäť je obmedzená a kompilátory sú tu na to, aby nám ľuďom pomohli.

Typový systém nielenže urobí naše údaje konzistentnejšími, ale môže tiež poskytnúť automatické dopĺňanie pre dátové typy. Pozná typy, takže môže ukázať členom údaje. Na túto myšlienku sa pozrieme neskôr. Tu som len chcel ukázať, že v hlavách premýšľame typmi.

Jednoduché typy a jednoduché použitie

Sme pripravení použiť niektoré silne napísané programovacie jazyky, ako napríklad strojopis. Jednoducho musíme explicitne pridať typové anotácie do našich dátových štruktúr. Je to jednoduché, nie?

Niekedy to však nie je také jednoduché (zvyčajne to nie je ľahké, ak pochádzate z dynamicky písaných jazykov. Cítite sa neproduktívne. Pripadá vám to ako boj proti typom). Ide o to, aby bola táto krivka učenia hladšia a zábavnejšia.

Tu uvidíme veľa príkladov, ako používať typy v strojopisu. Začneme jednoduchými a hlúpymi príkladmi a postupne to urobíme komplexnejšími pri navrhovaní mentálneho modelu na typové myslenie.

Rovnako ako v Javascripte, aj strojopis obsahuje základné typy údajov, ako | _+_ |, | _+_ |, | _+_ |, | _+_ | atď. Všetky základné typy údajov nájdete v Dokumenty strojopisu .

Vďaka týmto jednotkám údajov môžeme naše programy urobiť užitočnejšími. Aby to bolo praktickejšie, uvedieme si jednoduchý príklad. A | _+_ | funkciu.

Ako to funguje v Javascripte?

const product = { title: 'Some product', price: 100.00, };

Všetko v poriadku? Dobre.

Teraz to použijeme:

const products = [ { title: 'Product 1', price: 100.00, }, { title: 'Product 2', price: 25.00, }, { title: 'Product 3', price: 300.00, } ];

Očakávame, že sa v našom systéme uskutočnia prvé dve telefonáty. Javascript je však veľmi flexibilný a umožňuje nám poskytnúť tejto funkcii akúkoľvek hodnotu.

Posledný hovor je bizarný. Môžeme volať pomocou reťazca, ale vráti to neočakávaný výsledok. Neruší sa to vo vývoji, ale bude to mať za následok podivné správanie počas behu.

Čo chceme? Chceme do funkcie pridať niekoľko obmedzení. Bude môcť prijímať iba čísla. Zúžime tým možnosť neočakávaného správania. A typ návratovej funkcie je tiež číslo.

function sumAllPrices(products) { return products.reduce((sum, product) => sum + product.price, 0); }; sumAllPrices(products); // 425

Skvelé! Bolo to veľmi jednoduché. Zavolajme znova.

reduce

Pri zadávaní anotácií našej funkcie poskytujeme kompilátoru informácie, aby zistil, či je všetko správne. Bude nasledovať obmedzenia, ktoré sme do funkcie pridali.

Prvé dve výzvy sú teda rovnaké ako v Javascripte. Vráti správny výpočet. Ale v poslednom z nich máme chybu v čase kompilácie. Toto je dôležité. Chyba sa teraz stane v čase kompilácie a bráni nám odoslať nesprávny kód do výroby. Hovorí sa, že | _+_ | typ nie je súčasťou súboru hodnôt v | _+_ | typ vesmíru.

Pri základných typoch stačí pridať dvojbodku, za ktorou nasleduje definícia typu.

Array

Teraz zvýšime výzvu. Pamätáte si kód objektu výrobku, ktorý sme napísali v JavaScripte? Implementujme to znova, ale teraz s myšlienkou na strojopis.

Len si pamätáme, o čom hovoríme:

price

Toto je hodnota produktu. Má | _+_ | ako | _+_ | a | _+_ | ako | _+_ |. Práve to je to, čo potrebujeme vedieť.

Typ objektu by bol takýto:

product.price

Tento typ používame na anotáciu našej funkcie:

products

Pri tomto type bude kompilátor vedieť, ako zaobchádzať s nekonzistentnými údajmi:

krypto bonusový míľový token
reduce

Tu sa delí na dve rôzne vlastnosti:

  • | _+_ | je | _+_ | a nemali by ste dostať | _+_ |.
  • | _+_ | je | _+_ | a nemali by ste dostať | _+_ |.

Kompilátor nám pomáha zachytiť také chyby typu.

Túto anotáciu tohto typu by sme mohli vylepšiť pomocou konceptu s názvom | _+_ |. Je to spôsob, ako vytvoriť nový názov pre konkrétny typ.

V našom prípade by typ produktu mohol byť:

Array

Je lepšie vizualizovať typ, pridať sémantiku a možno ho znova použiť v našom systéme.

Teraz, keď máme tento typ produktu, môžeme ho použiť na napísanie zoznamu produktov. Syntax vyzerá takto: | _+_ |. V našom prípade | _+_ |.

produce

Teraz funkcia | _+_ |. Obdrží produkt a vráti číslo, súčet cien všetkých produktov.

price

To je veľmi zaujímavé. Keď píšeme produkt, keď píšeme | _+_ |, zobrazí možné vlastnosti, ktoré môžeme použiť. V prípade typu výrobku zobrazí vlastnosti | _+_ | a | _+_ |.

number

Absolvovanie | _+_ | bude mať za následok hodnotu | _+_ |. Prázdny zoznam bude mať za následok hodnotu | _+_ |. A ak prejdeme objekt s inou štruktúrou - Strojopis má systém štruktúrnych typov a tejto téme sa budeme venovať hlbšie neskôr - prekladač vyvolá chybu typu, ktorá hovorí, že štruktúra nie je súčasťou | _+_ | typ.

Štrukturálne písanie

Štrukturálne písanie je typom kompatibility typov. Je to spôsob, ako porozumieť kompatibilite medzi typmi na základe jeho štruktúry: funkcie, členy, vlastnosti. Niektoré jazyky majú kompatibilitu typov na základe názvov typov a nazýva sa to nominálne písanie.

Napríklad v Jave, aj keď majú rôzne typy rovnakú štruktúru, vyvolá to chybu pri kompilácii, pretože na vytváranie inštancií a definovanie novej inštancie používame iný typ.

string

V systémoch nominálneho typu je relevantnou časťou typu názov, nie štruktúra.

Typescript na druhej strane overuje štrukturálnu kompatibilitu, aby povolil alebo nie konkrétne údaje. Jeho typový systém je založený na štrukturálnom písaní.

Rovnaká implementácia kódu, ktorá zlyhala v Jave, by fungovala aj v strojopisu.

boolean

Chceme použiť | _+_ | typu a má vlastnosť | _+_ |, aby ukazoval na | _+_ | typ. Má tiež typ vlastnosti. Strojopis teda pochopí, že oba typy majú rovnaký tvar.

Nejde však len o triedy, ale funguje to aj pre akékoľvek iné objekty.

null

Tento kód sa kompiluje aj preto, že tu máme rovnakú štruktúru. Systému strojopisu nezáleží na tom, či ide o triedu alebo o doslovný objekt, ak má rovnakých členov, bude flexibilný a kompilovateľný.

Teraz však pridáme tretí typ: | _+_ |.

sum

Má nielen | _+_ | majetku, ale aj | _+_ |. Čo by sa stalo, keby sme vytvorili inštanciu | _+_ | inštancia v konštante typu | _+_ |?

function sum(a, b) { return a + b; }

Kompilátor to neakceptuje. Chceme použiť | _+_ |, ktorý má | _+_ | a | _+_ |. Vytvárame však inštanciu | _+_ | ktorý má iba | _+_ | nehnuteľnosť. Nemá teda rovnaký tvar. Spôsobí to chybu:

sum(1, 2); // 3 sum(2, 2); // 4 sum(0, 'string'); // '0string' WTF!

Naopak by to fungovalo, pretože chceme | _+_ | a | _+_ | má všetky vlastnosti (| _+_ |) z | _+_ |.

function sum(a: number, b: number): number { return a + b; }

Funguje to dobre!

Môžeme pokračovať vo enumoch, literáloch objektov a akomkoľvek inom type, ale ide tu o to, aby sme pochopili, že relevantnou súčasťou je štruktúra typu.

Čas behu a kompilácie

Toto je oveľa komplexnejšia téma v teórii programovacieho jazyka, ale chcel by som uviesť niekoľko príkladov na rozlíšenie runtime od času kompilácie.

Runtime je v zásade doba vykonávania programu. Predstavte si, že váš koncový server prijíma údaje zo stránky formulára klientskeho rozhrania, spracováva tieto údaje a ukladá ich. Alebo keď váš frontend požaduje od servera údaje na vykreslenie zoznamu produktov Pokemons.

Čas kompilácie je v zásade vtedy, keď kompilátor vykonáva operácie v zdrojovom kóde, aby uspokojil požiadavky programovacieho jazyka. Môže to zahŕňať napríklad kontrolu typu ako operáciu.

Chyby pri kompilácii v strojopisu napríklad veľmi súvisia s kódom, ktorý sme napísali predtým:

  • Keď v type chýba vlastnosť: | _+_ |
  • Keď sa typ nezhoduje: | _+_ |

Pozrime sa na niekoľko príkladov, aby sme lepšie porozumeli.

Chcem napísať funkciu na získanie indexu časti schváleného programovacieho jazyka.

sum(1, 2); // 3 sum(2, 2); // 4 sum(0, 'string'); // Argument of type ''string'' is not assignable to parameter of type 'number'.

Prijíma | _+_ | a | _+_ | ktoré budeme hľadať, aby sme získali index.

string

Pri prechode reťazca to funguje dobre. Pri odovzdávaní čísla sa však vyskytla chyba za behu | _+_ |. Pretože číslo nemá | _+_ | funkciu, takže ju nemôžeme skutočne používať.

Ale ak poskytneme kompilátoru informácie o type, v čase kompilácie to spôsobí chybu pred spustením kódu.

number

Teraz náš program vie, že bude musieť prijať dva reťazce a vrátiť číslo. Kompilátor môže použiť tieto informácie na vyhodenie chýb, keď dostaneme chybu typu ... pred spustením.

const isTypescript: boolean = true; const age: number = 24; const username: string = 'tk';

Možno pre malé projekty (alebo malé funkcie, ako sú tie naše) v skutočnosti nevidíme príliš veľký prínos.

V tomto prípade vieme, že musíme odovzdať reťazec, takže funkcii neprenesieme číslo. Ale keď sa základňa kódov rozrastie alebo máte veľa ľudí, ktorí pridávajú kód a sú zložitejšie, je mi jasné, že typový systém nám môže veľmi pomôcť pri vytváraní chýb v čase kompilácie pred odoslaním kódu do výroby.

Najprv potrebujeme celú krivku učenia, aby sme porozumeli typom a všetkým mentálnym modelom, ale po chvíli budete viac zvyknutí písať anotácie a nakoniec sa spriateliť s prekladačom. Bolo by a pomocník , nie a jačať .

Keď sa učíme o základnom rozdiele medzi časom kompilácie a časom spustenia, myslím si, že je skvelé odlíšiť typy od hodnôt.

Všetky príklady, ktoré tu ukážem, je možné skopírovať a spustiť v Strojopisné ihrisko porozumieť kompilátoru a výsledku procesu kompilácie (aka Javascript ).

V strojopisu máme dva rôzne vesmíry: medzery medzi hodnotami a typmi. Typový priestor je miesto, kde sú typy definované a používané, aby kompilátor dokázal všetky veľké kúzla. A priestor hodnôt sú hodnoty v našich programoch, ako sú premenné, konštanty, funkcie, literály hodnôt a veci, ktoré máme za behu.

Je dobré porozumieť tomuto konceptu, pretože v strojopisu nemôžeme používať kontrolu typu za behu. Má veľmi jasné oddelenie medzi kontrolou typu a procesom kompilácie.

Typescript má za následok typovú kontrolu typov zdrojových kódov a zisťovanie, či je všetko správne a konzistentné. A potom sa môže skompilovať do Javascriptu.

Pretože sú tieto dve časti oddelené, nemôžeme používať kontrolu typu za behu. Iba v čase kompilácie. Ak sa pokúsite použiť typ ako hodnotu, vyvolá to chybu: | _+_ |.

Pozrime sa na príklady tejto myšlienky.

Predstavte si, že chceme napísať funkciu s názvom | _+_ | kde obdržíme spôsob platby a na základe tohto spôsobu chceme vykonať nejakú akciu. Máme kreditnú a debetnú kartu. Definujme ich tu:

const product = { title: 'Some product', price: 100.00, };

Tieto typy sú v Zadajte priestor , takže funguje iba v čase kompilácie. Po kontrole typu tejto funkcie kompilátor odstráni všetky typy.

Ak pridáte tieto typy na ihrisko Typescript, výstup bude mať iba striktnú definíciu | _+_ |.

Cieľom je skutočne pochopiť, že typy žijú v Zadajte priestor a nebude k dispozícii za behu. V našej funkcii to teda nebude možné urobiť:

title

V kompilátore vyvolá chybu: | _+_ |.

Kompilátor pozná rozdiel medzi týmito dvoma medzerami a typ | _+_ | žije v Zadajte priestor .

Ihrisko je veľmi efektívny nástroj na zobrazenie výstupu vášho strojopisného kódu. Ak vytvoríte nový predmet kreditnej karty takto:

string

Kompilátor napíše kontrolu a vykoná všetky kúzla a potom preloží kód strojopisu do jazyka Javascript. A máme toto:

price

Rovnaký objekt, ale teraz iba s hodnotou a bez typu.

#typescript #javascript #developer

www.freecodecamp.org

Vysvetlené typy strojopisu - mentálny model, ktorý vám pomôže premýšľať nad typmi

Tento príspevok je mojou snahou pomôcť vývojárom viac premýšľať v typoch a porozumieť tomuto mentálnemu modelu. Myslenie v typoch JavaScript. Jednoduché typy a jednoduché použitie. Štrukturálne písanie. Obmedzenia a zúženie typu. Zloženie typu