{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/ciekawostki-typescript-2-ts-minus-typy-rowna-sie-js","result":{"data":{"markdownRemark":{"html":"<h2>TypeScript nadzbiorem JavaScriptu</h2>\n<p>Mówi się, że \"TypeScript jest nadzbiorem JavaScriptu\". Ale co to oznacza? W praktyce - wiadomo - każdy kod JavaScriptu jest poprawnym kodem JavaScriptowym. Zatem, co jest tym \"nad\" w stosunku do JavaScriptu? Otóż - system typów. I - przynajmniej koncepcyjnie, z pewnymi drobnym zastrzeżeniami, o których niżej - tylko system typów. To znaczy, że - \"kanonicznie\" (zastrzeżnia niżej) - konwersja TS do JS polega tylko na usunięciu informacji o typach. A zatem właściwie taką \"konwersję\" można by wykonać ręcznie usuwając wszystkie typy czy informacje, że dana klasa implementuje jakiś interfejs.</p>\n<p>To, co napisałem powyżej, można dobrze zaobserwować na przykładzie typescriptowych modyfikatorów dostępu w klasie. Wyobraźmy sobie, że mamy taką klasę, napisaną w TS:</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Person</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">private</span> firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span>\n  <span class=\"token keyword\">private</span> lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span>\n\n  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span>firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>firstName <span class=\"token operator\">=</span> firstName\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>lastName <span class=\"token operator\">=</span> lastName\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">public</span> <span class=\"token function\">sayHello</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Hi, I'm </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>firstName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>lastName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">!</span><span class=\"token template-punctuation string\">`</span></span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Pola <code class=\"language-text\">firstName</code> i <code class=\"language-text\">lastName</code> zadeklarowaliśmy jako prywatne. Zatem w TS próby dostania się do nich zakończą się błędem:</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">const</span> john <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Person</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"John\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Smith\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token builtin\">console</span><span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>john<span class=\"token punctuation\">.</span>firstName<span class=\"token punctuation\">)</span> <span class=\"token comment\">// &lt;- tu będzie błąd</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span></span></pre></div>\n<p>Jak ta klasa zostanie jednak przekonwertowana do JavaScriptu? Mniej więcej tak:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-javascript line-numbers\"><code class=\"language-javascript\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Person</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">firstName<span class=\"token punctuation\">,</span> lastName</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>firstName <span class=\"token operator\">=</span> firstName\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>lastName <span class=\"token operator\">=</span> lastName\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token function\">sayHello</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Hi, I'm </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>firstName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>lastName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">!</span><span class=\"token template-punctuation string\">`</span></span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>A gdybyśmy w JavaScripcie chcieli się dostać do <code class=\"language-text\">firstName</code>? Proszę bardzo - <strong>błędu nie ma</strong>:</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-javascript line-numbers\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> john <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Person</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"John\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"Smith\"</span><span class=\"token punctuation\">)</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>john<span class=\"token punctuation\">.</span>firstName<span class=\"token punctuation\">)</span> <span class=\"token comment\">// &lt;- błędu nie ma!</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span></span></pre></div>\n<p>Gdy pierwszy raz się o tym dowiedziałem, to pomyślałem: \"Ale jak to? Prywatne pole jest publiczne?... TypeScript, oszukałeś mnie...\" Ale w zasadzie to jest konsekwencja tego równania:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-text line-numbers\"><code class=\"language-text\">TypeScript - (system typów) = JavaScript</code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<p>Jeśli zatem chcielibyśmy na 100% traktować te pola jako prywatne - bo np. piszemy bibliotekę i naprawdę chcemy ukryć jakiś szczegół implementacyjny - to mamy dwa wyjścia:</p>\n<ul>\n<li>skorzystanie z eksperymentalnej notacji pól prywatnych w JS - <code class=\"language-text\">#</code> (<a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields\">tutaj opis tej notacji</a>),</li>\n<li>skorzystanie z domknięć (patrz niżej).</li>\n</ul>\n<p>W przypadku domknięć, należałoby napisać w TS naszą klasę mniej więcej tak:</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Person</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">public</span> <span class=\"token function-variable function\">sayHello</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token builtin\">string</span>\n\n  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span>firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span><span class=\"token function\">sayHello</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Hi, I'm </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>firstName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>lastName<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\">!</span><span class=\"token template-punctuation string\">`</span></span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>To rozwiązanie też ma niestety swoje wady:</p>\n<ul>\n<li>jeśli chcemy skorzystać z ukrtych danych w metodzie klasy, to musimy ją zdefiniować w konstruktorze,</li>\n<li>każda instacja klasy ma kopię tych metod zdefiniowanych w konstruktorze, co zwiększa zużycie pamięci.</li>\n</ul>\n<h2>Wyjątki od reguły</h2>\n<p>Na koniec muszę zwrócić uwagę na dwa wyjątki od tej zasady, że transpilator jedynie usuwa informacje o typach i modyfikatory dostępu. Tymi wyjątkami są enumy oraz pewien <em>syntactic sugar</em> w postaci definiowania parametrów konstruktora od razu jako pól klasy.</p>\n<h3>Enumy</h3>\n<p>Dla programisty C#, który zaczyna przygodę z TypeScriptem - użycie enumów to coś naturalnego: przecież nie będziemy używać jakichś <em>magic numberów</em>! Jednakże enumy w TS zachowują się nietypowo.\nPo pierwsze, enum z wartościami liczbowymi pozwala na przypisanie do niego dowolnej liczby... (Co to za enum?!)</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">enum</span> WeekDay <span class=\"token punctuation\">{</span>\n  Monday <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n  Tuesday <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n  Wednesday <span class=\"token operator\">=</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n  Thursday <span class=\"token operator\">=</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span>\n  Friday <span class=\"token operator\">=</span> <span class=\"token number\">5</span><span class=\"token punctuation\">,</span>\n  Saturday <span class=\"token operator\">=</span> <span class=\"token number\">6</span><span class=\"token punctuation\">,</span>\n  Sunday <span class=\"token operator\">=</span> <span class=\"token number\">6</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> wtf<span class=\"token operator\">:</span> WeekDay <span class=\"token operator\">=</span> <span class=\"token number\">11</span> <span class=\"token comment\">// &lt;-- nie ma błędu!</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Po drugie, jeśli do deklaracji enuma dodamy const (a więc <code class=\"language-text\">const enum</code>), to wszystkie jego użycia zostaną potraktowane jak <code class=\"language-text\">const</code> w C# - w czasie transpilacji zostaną podmienione na wartości liczbowe.</p>\n<p>Po trzecie, enumy z wartościami stringowymi mają pewne pułapki: jeśli przypiszemy enuma do zmiennej, to zmiast typu string, otrzyma on typ literałowy, więc nie będziemy mogli go nadpisać, np.:</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">enum</span> Status <span class=\"token punctuation\">{</span>\n  Pending <span class=\"token operator\">=</span> <span class=\"token string\">\"pending\"</span><span class=\"token punctuation\">,</span>\n  Done <span class=\"token operator\">=</span> <span class=\"token string\">\"done\"</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">let</span> statusText <span class=\"token operator\">=</span> Status<span class=\"token punctuation\">.</span>pending\nstatusText <span class=\"token operator\">=</span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Status is: </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>statusText<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span> <span class=\"token comment\">// &lt;-- tu będzie błąd: \"Type 'string' is not assignable to type 'Status'.\"</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Zamiast enuma lepiej użyć tutaj \"unię typów literałowych\", czyli:</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">type</span> <span class=\"token class-name\">Status</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"pending\"</span> <span class=\"token operator\">|</span> <span class=\"token string\">\"done\"</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span></span></pre></div>\n<h3>Parametry konstruktora jako pola</h3>\n<p>TypeScript umożliwia zrobienie takie skrótowego zapisu:</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Person</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">public</span> firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">public</span> lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span></span></pre></div>\n<p>zamiast rozwlekłego:</p>\n<div class=\"gatsby-highlight\" data-language=\"typescript\"><pre style=\"counter-reset: linenumber NaN\" class=\"language-typescript line-numbers\"><code class=\"language-typescript\"><span class=\"token keyword\">class</span> <span class=\"token class-name\">Person</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">public</span> firstName<span class=\"token operator\">:</span> stirng\n  <span class=\"token keyword\">public</span> lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span>\n  <span class=\"token function\">constructor</span><span class=\"token punctuation\">(</span>firstName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> lastName<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>firstName <span class=\"token operator\">=</span> firstName\n    <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>lastName <span class=\"token operator\">=</span> lastName\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code><span aria-hidden=\"true\" class=\"line-numbers-rows\" style=\"white-space: normal; width: auto; left: 0;\"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></pre></div>\n<p>Ten <em>syntactic sugar</em> jest dla TS wyjątkowy, bo właśnie też skutkuje generowanie kodu JS - czyli znów wyłamujemy się z reguły \"TS minus typy to JS\". Autor książki, o której wspominam poniżej, krytykuje używanie tego \"myku\" w TS (właśnie z takich powodów, nazwijmy to, kanonicznych), jednak dla mnie jest to bardzo wygodne. Ponadto, podobną propozycję widziałem w którejś z przyszłych/eksperymentalnych wersji C#, więc być może to jest też jakiś trend wspólny dla różnych języków. :)</p>\n<p>Ten wpis jest częścią serii o TypeScripcie, inspirowaną lekturą <a href=\"https://helion.pl/ksiazki/typescript-skuteczne-programowanie-dan-vanderkam,e_1lgp.htm\">książki D. Vanderkama pt. \"TypeScript. Skuteczne programowanie\"</a>.</p>","excerpt":"TypeScript nadzbiorem JavaScriptu Mówi się, że \"TypeScript jest nadzbiorem JavaScriptu\". Ale co to oznacza? W praktyce - wiadomo - każdy kod JavaScriptu jest…","frontmatter":{"date":"01 October, 2020","path":"/blog/ciekawostki-typescript-2-ts-minus-typy-rowna-sie-js","title":"Ciekawostki Typescript #2 - TS - typy = JS"},"fields":{"readingTime":{"text":"4 min read"}}}},"pageContext":{}},"staticQueryHashes":["3649515864","63159454"]}