TypeScript
TypeScript

TypeScript a jeho základní typy

Pavel  JaklPavel Jakl,

Každý vývojář zná ten pocit. Strávíte hodiny psaním javascriptového kódu, jste připraveni ho spustit, a pak... nic. Výsledek není takový, jaký jste očekávali. Vše se zdá vše v pořádku, bez jakýchkoli chyb. Ale po detailním prozkoumání kódu narazíte na banální chybu: neuzavřená závorka, nesprávné datové typy, přístup k neexistující hodnotě objektu, nebo dokonce obyčejný překlep. Moderní vývojové prostředí, jako je Visual Studio Code nebo WebStorm, mohou pomoci odhalit řadu těchto problémů, ale některé aspekty, zejména ty související s datovými typy a logikou, vyžadují pečlivou pozornost vývojáře. V malých aplikacích a skriptech je to frustrující, ale zvládnutelné. Co však ve větších projektech, kde je udržitelnost a spolehlivost klíčová?

V tomto článku se podíváme na to, jak Typescript - robustní nástroj, který rozšiřuje standardní JavaScript - může být řešením těchto běžných výzev. Představíme si základní datové typy a jak lze pomocí Typescriptu předcházet chybám ještě před spuštěním kódu, zvyšovat čitelnost a udržovatelnost velkých aplikací, a zároveň si udržet flexibilitu a dynamiku, kterou JavaScript nabízí. 

TypeScript

Typescript je programovací jazyk, který stojí na základech JS, rozšiřuje jeho funkcionalitu, a přidává funkce, které nejsou v běžném JS dostupné. TS je staticky typovaný oproti čistému JS, který je typovaný dynamicky a typy proměnných tak nemohou být za běhu přetypovány. (více o TS)

Typescript provádí statickou kontrolu chyb v kódu a upozorní nás na všechny potencionální chyby ještě před tím, než je script interpretován, tudíž můžeme vzniklé problémy vyřešit přímo při psaní kódu.

Obecná instalace

Instalace Node.js TypeScript vyžaduje Node.js. Pokud jej ještě nemáte, stáhněte a nainstalujte nejnovější verzi z oficiálních stránek Node.js.

Instalace TypeScriptu Otevřete příkazovou řádku nebo terminál a zadejte následující příkaz k instalaci TypeScriptu (globálně nebo pro projekt):

npm install -g typescript //globálně
npm install --save-dev typescript // pro určitý projekt

Ověření instalace Po instalaci ověřte, že byl TypeScript správně nainstalován, zadáním:

tsc --version

Další možností instalace, pokud vytváříte nový projekt, je přímá integrace TypeScriptu již na samém počátku. Tuto možnost nabízejí mnohé front-endové frameworky. Během instalace aplikace si můžete zvolit, zda do projektu chcete přidat TypeScript.

Tím je TypeScript nainstalován a můžete jej ihned začít využívat. Samozřejmě, výběr závisí na typu projektu, na kterém pracujete. Pokud využíváte některý z populárních frameworků, jako je React, Vue.js či Nuxt, způsob integrace TypeScriptu se může lišit. Jestliže chcete TypeScript integrovat do již existující aplikace, je také třeba zvážit specifika použitých technologií.

Při rozhodování o tom, jak správně nainstalovat TypeScript pro vaše potřeby, je důležité se podrobně seznámit s dokumentací a doporučenými postupy pro daný framework či technologii.

Základní typy

Primitivní Datové Typy

V programování se setkáváme s několika primitivními datovými typy, které zahrnují:

  • string - textový řetězec
  • number - číslo, JS nerozlišuje int a float
  • boolean - logická hodnota

TypeScript umožňuje definovat typy proměnných dvěma způsoby. První z nich je implicitní dedukce typu z přiřazené hodnoty. Například:

let lastName = "Novotný"; // TypeScript automaticky odvodí, že lastName je typu string

Druhým způsobem je explicitní deklarace typu proměnné:

let stringType: string = "HelloWorld";
let numberType: number = 55;
let booleanType: boolean = true;

TypeScript poskytuje silnou typovou kontrolu. Pokud máme proměnnou message deklarovanou jako string, očekáváme, že obsahuje text. Pokud se pokusíme přiřadit hodnotu jiného typu, TypeScript nám oznámí chybu.

let message: string;
message = 55; // Type 'number' is not assignable to type 'string'.

Díky lokální deklaraci proměnných můžeme mít jistotu, že v rámci souboru bude proměnná message vždy obsahovat textové hodnoty.

Práce s poli

V TypeScriptu můžeme deklarovat pole s definovaným typem prvků dvěma způsoby. Představme si, že chceme vytvořit pole, které bude obsahovat pouze číselné hodnoty. Můžeme to udělat takto:

Použitím hranatých závorek pro definici typu. Například:

let codes: number[] = [1, 3, 4, 6, 10];

Použitím obecného typu Array, kde specifikujeme typ prvků uvnitř špičatých závorek. Například:

let codes: Array<number> = [1, 3, 4, 6, 10];

Obě tyto metody jsou v TypeScriptu rovnocenné a výběr mezi nimi závisí na preferencích programátora nebo na konvencích používaných v projektu. V obou případech deklarujeme pole codes, které může obsahovat pouze číselné hodnoty. Pokud bychom do pole chtěli přiřadit jinou hodnotu než číslo, TS se opět ohlásí s chybou.

Typ any

V TypeScriptu se setkáváme s univerzálním typem nazývaným any. Tento typ je zvlášť užitečný v situacích, kdy nechceme, aby hodnoty způsobovaly problémy během procesu kontroly typů.

Klíčové vlastnosti typu 'any':

  1. Flexibilita: Hodnota typu any umožňuje přistupovat ke všem jejím vlastnostem, přičemž tyto vlastnosti také nabydou typu any.
  2. Volání jako funkce: Hodnotu typu any lze volat jako funkci.
  3. Přiřazování hodnot: Hodnotu typu any lze přiřadit jakémukoliv jinému typu a naopak.
  4. Syntaktická svoboda: S hodnotou typu any můžete provádět jakoukoli syntakticky legální operaci.

Proč používat typ 'any'?

Typ any je ideální, pokud nechcete trávit čas specifikací komplexního typu, který by TypeScript akceptoval. Je to rychlé a flexibilní řešení pro různé situace, kde detailní typování není prioritní nebo kdy je příliš složité.

V situacích, kdy není typ specifikován a kompilátor jej nemůže odvodit z kontextu, výchozím typem se stává any. Přesto je doporučeno se tomuto přístupu vyhnout, jelikož použití typu any v praxi odstraňuje výhody striktní typové kontroly, které TypeScript nabízí.

Funkce

Funkce jsou klíčovým prostředkem pro předávání dat v JavaScriptu a TypeScript nabízí možnosti, jak typovat jak vstupní, tak i výstupní hodnoty funkcí.

Typování parametrů

V TypeScriptu můžeme pomocí anotací definovat typy parametrů funkcí. Například:

// Funkce očekává parametr typu string

function saySomething(message: string) {
   console.log(message);
}
saySomething("Hello TypeScript");

Pokud se pokusíme do funkce poslat hodnotu jiného typu, TypeScript nás na tuto chybu upozorní:

// Runtime error při spuštění

saySomething(50); // Chyba: Funkce očekává text, nikoli číslo

Návratová hodnota

Pro lepší kontrolu nad chováním funkcí můžeme také definovat typ jejich návratové hodnoty:

function saySomething(message: string): string { // Funkce vrací textovou hodnotu
   return message;
}
saySomething("Hello TypeScript");

Ačkoliv TypeScript umí odvodit návratový typ funkce z jejího těla, je často užitečné typ explicitně uvést. To usnadňuje porozumění kódu ostatním vývojářům, na první pohled je jasně vidět, co funkce přijímá a co vrací a zjednodušuje tvorbu dokumentace.

Práce s objekty

V JavaScriptu a TypeScriptu jsou objekty jedním z nejpoužívanějších typů. Objekt je hodnota s vlastnostmi, a TypeScript umožňuje jejich přesné typování.

Definování objektových typů

Pro definování typu objektu stačí určit jeho vlastnosti a jejich typy. Jako příklad uvedeme funkci, která dostane informace o uživateli a vypíše je do konzole.

function userInformation(user: {firstname: string; lastname: string; age: number}) {
    console.log("Firstname: " + user.firstname )
    ...
    ...
}

V tomto příkladu má funkce userInformation parametr user, který je objektem s vlastnostmi firstname, lastname a age. TypeScript upozorní na chybu, pokud objekt neposkytne všechny vlastnosti nebo mají vlastnosti špatný typ. Parametr user by šel samozřejmě zapsat jiank, vytvořit interface userInterface a do funkce předat user: userInterface, ale o tom někdy příště. Pokud bychom chtěli nějakou vlastnost objektu specifikovat jen v nějakém případě, jako nepovinnou vlastnost, můžeme použít tzv. optional properties (přidání ? za název vlastnosti).

function userInformation(user: {firstname: string; lastname: string; age?: number}) {
	 // zpracování informací o uživateli
}

Práce s nepovinnými vlastnostmi

Je důležité si být vědom toho, že nepovinné vlastnosti mohou mít hodnotu undefined. Proto je třeba zkontrolovat, zda jsou definované, předtím než s nimi provedeme nějaké operace. V moderním JavaScriptu a TypeScriptu to lze udělat pomocí tzv. optional chaining (?.), který nám umožňuje bezpečně pracovat s hodnotami, které nemusí být vždy definovány. Například:

user.age?.toString(); // Bezpečně převede age na string, pokud je definován

Union typy v TypeScriptu

TypeScript je bohatý jazyk, který nám umožňuje vytvářet nové typy z již existujících pomocí různých operátorů. Jedním způsobem kombinování typů je využití tzv. union typu. Union typ je složený z dvou nebo více různých typů a umožňuje proměnným nabývat hodnot jakéhokoli z těchto typů. Každý typ, který je součástí union typu, označujeme jako člen unionu.

Představme si funkci, která vrací ID. Nejistota, zda bude ID typu string nebo number, nás vede k použití union typu:

function getId(id: string | number): string | number {
    // Tato funkce vrátí ID buď jako number, nebo jako string
}

Pokud s hodnotou chceme dále pracovat, operace musí být platná pro každý člen union typu. Pokud bychom chtěli použít například metodu toUpperCase(), TypeScript nám odpoví chybou, protože tato metoda existuje pouze pro string, nikoli pro string | number. Proto musíme použít typeof pro zúžení typu:

if (typeof id === "string") {
    id.toUpperCase(); // Platné pouze pro string
}

Využití v poli

Pokud bychom chtěli vytvořit funkci pro zpracování počtu druhů ovoce, můžeme ji navrhnout tak, aby přijímala buď pole stringů nebo jediný string:

function printFruits(fruits: string[] | string) {
    // Kód pro zpracování hodnoty fruits
}

Pokud bychom chtěli s hodnotou funkce dále pracovat a máme využitý union type v parametru funkce, můžeme odlišit, jestli je hodnota ve fuknci pole nebo jen string. Tuto podmínku můžeme formulovat následujícím způsobem: 

function printFruits(fruits: string[] | string) {
   if(Array.isArray(fruits)){
   		console.log("Fruits je pole")
   }
  // práce se string hodnotou
}

Společné vlastnosti a metody v union typech

Někdy mají členy union typu společné vlastnosti a metody, například metodu slice(), která je přítomna jak u polí, tak u řetězců nebo toString() pro boolean hodnoty, čísla a objekty. V takovém případě můžeme tuto metodu použít bez zúžení typů. Příklad společné vlastnosti může být například length, což je vlastnost, která je přítomna u řetězců a polí.

Konec první části :) 

Pokud vás láká TypeScript a chtěli byste si vyzkoušet základní koncepty prakticky, je pro vás připravený mini-projekt. V tomto projektu naleznete implementace všech funkcí, o kterých jsme si povídali v tomto článku.

Toto bylo základní přiblížení k TypeScriptu, jeho primárním typům a způsobům jejich jednoduchého použití. TypeScript je jazyk s bohatými možnostmi, a to, co jsme probrali, je jen malá část základů. Existuje mnohem více zajímavých konceptů, jako jsou type aliasy, interface, enumy, samotná konfigurace TypeScriptu a mnoho dalšího, které jsme zatím nezmínili. V nadcházejících článcích se ponoříme hlouběji do těchto dalších, pokoročilých témat a prozkoumáme, jak mohou obohatit vaše programovací dovednosti a projekty.

Pokud byste měli otázky, tak se určitě zastavte na náš Discord, kde můžeme vše prodiskutovat.

Zdroje

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html