From 13b4f573f20ffbbd57a38a68984215ced3173696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Jirs=C3=A1k?= Date: Tue, 28 May 2024 13:08:50 +0200 Subject: [PATCH] =?UTF-8?q?Dopln=C4=9Bn=C3=AD=20materi=C3=A1l=C5=AF=20pro?= =?UTF-8?q?=20bonusov=C3=A9=20lekce=20=E2=80=93=C2=A0TypeScript=20a=20Back?= =?UTF-8?q?end.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- daweb/bonus/backend/entry.yml | 5 + daweb/bonus/backend/ukazkovy-projekt.md | 3 + daweb/bonus/entry.yml | 5 + daweb/bonus/typescript/api.md | 98 ++++++++++++ daweb/bonus/typescript/cv-typescript.md | 3 + daweb/bonus/typescript/cvlekce/typescript.md | 9 ++ daweb/bonus/typescript/entry.yml | 10 ++ .../typescript/formulare-a-predavani-dat.md | 146 ++++++++++++++++++ daweb/bonus/typescript/komponenty-a-props.md | 90 +++++++++++ daweb/bonus/typescript/typescript-v-reactu.md | 13 ++ daweb/bonus/typescript/uvod-do-typescriptu.md | 120 ++++++++++++++ daweb/entry.yml | 1 + 12 files changed, 503 insertions(+) create mode 100644 daweb/bonus/backend/entry.yml create mode 100644 daweb/bonus/backend/ukazkovy-projekt.md create mode 100644 daweb/bonus/entry.yml create mode 100644 daweb/bonus/typescript/api.md create mode 100644 daweb/bonus/typescript/cv-typescript.md create mode 100644 daweb/bonus/typescript/cvlekce/typescript.md create mode 100644 daweb/bonus/typescript/entry.yml create mode 100644 daweb/bonus/typescript/formulare-a-predavani-dat.md create mode 100644 daweb/bonus/typescript/komponenty-a-props.md create mode 100644 daweb/bonus/typescript/typescript-v-reactu.md create mode 100644 daweb/bonus/typescript/uvod-do-typescriptu.md diff --git a/daweb/bonus/backend/entry.yml b/daweb/bonus/backend/entry.yml new file mode 100644 index 00000000..897ec904 --- /dev/null +++ b/daweb/bonus/backend/entry.yml @@ -0,0 +1,5 @@ +title: Úvod do backendu +lead: Jak si napsat jednoduchý backend pomocí Deno +access: claim +sections: + - ukazkovy-projekt diff --git a/daweb/bonus/backend/ukazkovy-projekt.md b/daweb/bonus/backend/ukazkovy-projekt.md new file mode 100644 index 00000000..52d806c4 --- /dev/null +++ b/daweb/bonus/backend/ukazkovy-projekt.md @@ -0,0 +1,3 @@ +## Ukázkový projekt + +Celá lekce se točí kolem ukázkového projektu, který najdete na GitHubu: [priklad-projekty](https://github.com/FilipJirsak-Czechitas/priklad-projekty). Popis použití je v `README` uvedeného projektu. \ No newline at end of file diff --git a/daweb/bonus/entry.yml b/daweb/bonus/entry.yml new file mode 100644 index 00000000..6e9959c5 --- /dev/null +++ b/daweb/bonus/entry.yml @@ -0,0 +1,5 @@ +title: Bonusy +lead: Volitelné lekce nad rámec témat akademie, ve kterých se můžete dozvědět něco navíc. +lessons: + - backend + - typescript diff --git a/daweb/bonus/typescript/api.md b/daweb/bonus/typescript/api.md new file mode 100644 index 00000000..0d91d406 --- /dev/null +++ b/daweb/bonus/typescript/api.md @@ -0,0 +1,98 @@ +## API v Typescriptu + +Dostáváme se do závěrečné fáze naší malé aplikace. Máme komponentu `Form`, která sbírá data od uživatele a máme komponentu `Activity`, která nám zobrazí vygenerovanou aktivitu. Nezbývá než vše dát dohromady a vytvořit funkci pro vygenerování activity. Proto si ukážeme, jak používat api volání v typescritpu. + +Vytvoříme si asynchronní funkci `fetchData`, která na vstupu bude očekávat informaci, o jakou aktivitu má uživatel zájem. Tuto informaci pak předáme v metodě fetch v url adrese. Funkce by nám na základě typu, měla vrátit jednu náhodnou aktivitu. + +```js +const fetchData = async (type: string) => { + const res = await fetch(`http://www.boredapi.com/api/activity?type=${type}`); + const data = await res.json(); + console.log(data); +}; +``` + +Takto získaná data musíme uložit do stavu, abychom s nimi mohli dál pracovat. Ovšem jakého budou datového typu? V reálném životě byste dostali strukturu dat od svých Backend kolegů, ale pro náš případ bude stačit, když se podíváme do konzole, co nám naše funkce `fetchData` vrátí. Vidíme, že je to objekt tvořený několika vlastnostmi, takže si stačí podle nich vytvořit interface. + +```js +interface ActivityDataStructure { + accessibility: number + activity: string; + key: string; + link: string; + participants: number; + price: number; + type: string; +} +... +const [activityData, setActivityData] = useState(); +``` + +Upravíme naši funkci `fetchData`, aby ukládala data do stavu. + +```js +const fetchData = async (type: string) => { + const res = await fetch(`http://www.boredapi.com/api/activity?type=${type}`); + const data = await res.json(); + setActivityData(data); +}; +``` + +Zbývají poslední dvě věci a to vytvořit si funkci, která z formuláře obdrží data od uživatele a odešleje pomocí Fetche. A pak už jen musíme zobrazit data, které obdržíme v odpověďi našeho volání. + +```js +const handleSubmitForm = (data: FormDataStructure) => { + fetchData(data.type); +}; +``` + +Výsledný kód v souboru `App.tsx` pak bude vypadat takto: + +```js +import { useState } from 'react'; +import { Activity } from './components/activity'; +import { Form, FormDataStructure } from './components/form'; +import './App.css'; + +interface ActivityDataStructure { + accessibility: number + activity: string; + key: string; + link: string; + participants: number; + price: number; + type: string; +} + +function App() { + const [activityData, setActivityData] = useState(); + + const fetchData = async (type: string) => { + const res = await fetch(`http://www.boredapi.com/api/activity?type=${type}`); + const data = await res.json(); + setActivityData(data); + } + + const handleSubmitForm = (data: FormDataStructure) => { + fetchData(data.type); + }; + + return ( + <> +
+ {activityData && ( + + )} + + ) +} + +export default App +``` diff --git a/daweb/bonus/typescript/cv-typescript.md b/daweb/bonus/typescript/cv-typescript.md new file mode 100644 index 00000000..20327098 --- /dev/null +++ b/daweb/bonus/typescript/cv-typescript.md @@ -0,0 +1,3 @@ +## Cvičení: Vyzkoušej si Typescript + +::exc[cvlekce/typescript] diff --git a/daweb/bonus/typescript/cvlekce/typescript.md b/daweb/bonus/typescript/cvlekce/typescript.md new file mode 100644 index 00000000..89ad45a9 --- /dev/null +++ b/daweb/bonus/typescript/cvlekce/typescript.md @@ -0,0 +1,9 @@ +--- +title: Jokes generator +demand: 3 +--- + +1. Stáhni si [vzorový projekt](https://github.com/Czechitas-podklady-WEB/jokes-demo-app) v Reactu. Nainstaluj závislosti a projekt si spusť. Podívej se jak vypadá v prohlížeči a jaký je jeho kód. +2. Pomocí vite a jeho šablony react-ts si vytvoř vlastní projekt. Tvým úkolem je naprogramovat stejnou aplikaci ovšem s použitím Typescriptu. +3. Můžeš kopírovat libovolný kód z původní aplikace, ulehčí ti to práci. Stejně tak si můžeš zkopírovat použité styly, ale neboj se zapojit i vlastní fantazii. +4. Pokud by tě napadlo jakékoli vylepšení, s chutí do něj a nezapomeň se pochlubit se svým výtvorem ostatním. diff --git a/daweb/bonus/typescript/entry.yml b/daweb/bonus/typescript/entry.yml new file mode 100644 index 00000000..7e9a5f5f --- /dev/null +++ b/daweb/bonus/typescript/entry.yml @@ -0,0 +1,10 @@ +title: Úvod do Typescriptu +lead: Co je to Typescript a jak ho v Reactu používat +access: claim +sections: + - uvod-do-typescriptu + - typescript-v-reactu + - komponenty-a-props + - formulare-a-predavani-dat + - api + - cv-typescript \ No newline at end of file diff --git a/daweb/bonus/typescript/formulare-a-predavani-dat.md b/daweb/bonus/typescript/formulare-a-predavani-dat.md new file mode 100644 index 00000000..9209503b --- /dev/null +++ b/daweb/bonus/typescript/formulare-a-predavani-dat.md @@ -0,0 +1,146 @@ +## Formuláře a předávání dat mezi komponentami + +V naší aplikaci budeme chtít aby si uživatel nechal vygenerovat vhodnou volnočasovou aktivitu na základě jeho preferencí. Pro začátek nám bude stačit, když ho necháme vybrat si, o jaký typ aktivity by měl zájem. A aby jsme mohli tuto informaci získat, musíme si na to vytvořit formulář, který bude uživatel vyplňovat. + +Vytvoříme si novou složku `Form`, kde si v `index.tsx` vytvoříme komponentu `Form`, která bude vracet jsx ve formátu: + +```js + {}}> + + + + +``` + +Komponenta má jediný úkol. Bude předávat vstup od uživatele do nadřazené komponenty. V jejím inteface bude tedy jediná props, která bude očekávat callback funkci, prostřednictvím, které předá data ven. + +```js +interface FormProps { + onSubmitForm: () => void; +} + +export const Form: React.FC = ({ onSubmitForm }) => { + return
...
; +}; +``` + +Od uživatele dostaneme dva údaje, jeho jméno a preferovaný typ aktivity. Budete tedy potřebovat stav, do kterého tyto údaje uložíme a bude potřeba aby jsme určili, jakého datového typu tyto data jsou. Opět k tomu použijeme interface. + +```js +interface FormDataStructure { + name: string; + type: string; +} + +export const Form: React.FC = ({ + onSubmitForm +}) => { + const [formData, setFormData] = useState({ + name: '', + type: '' + }); + ... +} +``` + +Vytvoříme si funkci `handleChange`, která nám bude poslouchat změny na formuláři, které provede uživatel a bude je ukládat do stavu. Taková funkce očekává vstup, který by měl být typu `event`, ale jaký přesně typ to je? S tím nám poradí vlastnost `onChange` u inputu. Stačí, když na ní najedem myší a typescript nám správný datový typ prozradí. + +```js + { + console.log(e); + }} + // (parameter) e: React.ChangeEvent +/> +``` + +Teď už víme, jaký datový typ potřebujeme a naše funkce `handleChange` bude vypadat takto: + +```js +const handleChange = (e: React.ChangeEvent) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); +}; +``` + +Ovšem ve formuláři máme ještě jiný element a to je `` neodpovídá datovému typu `ChangeEvent`, který očekává naše funkce `handleChange` jako vstup. V takovém případě nám nezbývá nic jiného než říci, že vstup u naší funkce, může být jeden nebo druhý datový typ. V řeči Typescriptu se jedná o Union types. Jednotlivé typy od sebe oddělujeme vertikální čárou `|`. + +```js +const handleChange = ( + e: React.ChangeEvent +) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); +}; +``` + +Teď už nám zbývá jen při odeslání formuláře předat data od uživatele ven z komponenty. Budeme tedy potřebovat funkci `handleSubmit`, která se o to postará. Protože budeme předávat do callback funkce stav `formData`, potřebujeme také upravit interface tak, aby props `onSubmitForm` očekávala vstup ve správném datovém typu. + +Výsledná komponenta `Form` bude vypadat takto: + +```js +import { useState } from "react"; + +interface FormProps { + onSubmitForm: (data: FormDataStructure) => void; +} + +interface FormDataStructure { + name: string; + type: string; +} + +export const Form: React.FC = ({ onSubmitForm }) => { + const [formData, setFormData] = useState({ + name: "", + type: "", + }) + + const handleChange = ( + e: React.ChangeEvent + ) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + onSubmitForm(formData); + }; + + return ( +
+ + + +
+ ); +}; +``` diff --git a/daweb/bonus/typescript/komponenty-a-props.md b/daweb/bonus/typescript/komponenty-a-props.md new file mode 100644 index 00000000..6839202a --- /dev/null +++ b/daweb/bonus/typescript/komponenty-a-props.md @@ -0,0 +1,90 @@ +## Komponenty a jejich props + +Představte si, že máte volný večer a nevíte, jakou ativitou ho vyplnit. Vytvoříme si proto aplikaci, která nám na základě vstupů od uživatele vrátí seznam možných aktivit, kterým bychom se mohli věnovat. + +Naši aplikaci si vybudujeme od těch nejjednodušších částí a proto si jako první vytvoříme komponentu, která nám bude návrhy na možné aktivity zobrazovat. + +V našem projektu si ve složce `src` vytvoříme složku `components` a v ní složku pro naši první komponentu v Typescriptu, kterou si pojmenujeme `Activity` a vytvoříme si v ní soubor `index.tsx`. +Protože používáme Typescript, tak naše soubory končí na `tsx` místo `jsx` a stejně tak soubory, které dříve používali čistý Javascript, tedy končily na `js`, budou v Typescriptu končit na `ts`. + +V `index.tsx` bude následující kód: + +```js +export const Activity = () => ( +
+

Name of the Activity:

+

Type:

+

Participants:

+

Price:

+
+); +``` + +Každá komponenta v Typescriptu by měla mít definovaný svůj typ. My používáme funkční komponenty, takže naše komponenta bude mít typ `FunctionComponent` nebo zkráceně `FC` a jsme v Reactu, takže naše komponenta bude vypadat takto: + +```js +export const Activity: React.FC = () => ( +... +); +``` + +Naše komponenta bude také očekávat nějaké vstupy, tedy props, a i ty musíme definovat. V Typescriptu se props u komponent definují pomocí `interface`, který se následně předává komponentě jako tzv. generický parametr. Ten se uvádí za definici typu komponenty mezi `<>`. + +```js +interface ActivityProps { + nameOfActivity: string; + type: string; + participants: number; + price: number; +} + +export const Activity: React.FC = ({ + nameOfActivity, + type, + participants, + price, +}) => ( +
+

Name of the Activity: {nameOfActivity}

+

Type:{type}

+

Participants: {participants}

+

Price: {price}

+
+); +``` + +Takto vytvořenou komponentu si naimportujeme do souboru `App.tsx`. Všimněte si, že nám ji Typescript červeně podtrhne a vyhodí chybu: + +```js +import { Activity } from "./components/activity"; + +function App() { + return ( + <> + // Error: Type '{}' is missing the following properties from + type 'ActivityProps': nameOfActivity, type, participants, price ts(2739) + + ); +} + +export default App; +``` + +Typescript nám říká, že komponenta vyžaduje vstupy, které jsou `nameOfActivity`, `type`, `participants` a `price`. Je tedy nutné tyto props u komponenty uvést a vložit do nich vstupy se správným datovým typem. Typescript nám tak napovídá, co komponenta potřebuje a zároveň nás hlídá, zda jí předáváme správné údaje. Použití naší komponenty by mělo vypadat nějak takto: + +```js +function App() { + return ( + <> + + + ); +} +``` + +Teď už umíme používat Typescript v jednoduchých komponenách a v další lekci si ukážeme jak pracovat s Typescriptem, pokud očekáváme nějaký vstup od uživatele a jak tento vstup předávat mezi komponentami. diff --git a/daweb/bonus/typescript/typescript-v-reactu.md b/daweb/bonus/typescript/typescript-v-reactu.md new file mode 100644 index 00000000..c83f3e4c --- /dev/null +++ b/daweb/bonus/typescript/typescript-v-reactu.md @@ -0,0 +1,13 @@ +## Typescript v Reactu + +V předchozí sekci jsme si řekli, proč Typescript používat a jaké základní typy máme. Dost bylo teorie a teď si ukážeme, jak se Typescript používá v praxi. + +Vytvoříme si novou složku, kde budeme mít náš testovací projekt. Založíme si zde reaktí aplikaci, kterou si založíme pomocí vite. Podívejte se na průvodce na stránce [vitejs.dev](https://vitejs.dev/guide/#scaffolding-your-first-vite-project), kde si můžete všimnou řady předpřipravených šablon, z nichž si vybereme šablonu `react-ts`. Náš instalační script bude vypadat takto: + +```js +npm create vite my-app -- --template react-ts +``` + +Vite nám sestaví základní kostru projektu a taktéž za nás nastaví Typescript. V aplikaci si můžete všimnout souboru `tsconfig.json`. Jedná se o klíčový soubor, protože obsahuje konfiguraci Typescriptu. Tímto souborem říkáme Typescriptu, jak se má v našem projektu chovat a to vůči vstupním souborům, jsx kódu, modulům, které můžeme instalovat až po výstupní soubory. + +Nastavování `tsconfig.json` se ovšem věnovat nebudeme. Podrobné informace naleznete na stránkách [typescriptlang.org](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). Všechno potřebné pro náš projekt už za nás nastavil vite. diff --git a/daweb/bonus/typescript/uvod-do-typescriptu.md b/daweb/bonus/typescript/uvod-do-typescriptu.md new file mode 100644 index 00000000..71425165 --- /dev/null +++ b/daweb/bonus/typescript/uvod-do-typescriptu.md @@ -0,0 +1,120 @@ +## Úvod do Typescriptu + +Co je to Typescript? Proč ho používat a proč ho milují davy FE vývojářů? +Mohli bychom říci, že je prostě boží. Ovšem my jsme zvídaví vývojáři, zajímá nás jak věci fungují a potřebujeme daleko lepší zdůvodnění než, že je něco boží. + +### Co je to Typescript a proč ho používat? + +Typescript je nadstavba nad Javascriptem, která přidává statický typový systém a další pokročilou funkcionalitu pro zvýšení bezpečnosti a efektivnosti při vývoji softwaru. + +To například znamená, že nám nedovolí do proměnné typu string uložit hodnotu typu number. + +```js +> let city: string = 'Praha'; +> city = 125; +ERROR: Type 'number' is not assignable to type 'string'. +``` + +Proč se Typescript používá: + +1. Statická typová kontrola: + Typescript umožňuje vyhledávání chyb v průběhu vývoje. + +2. Zlepšená čitelnost a dokumentace kódu: + Jasně definované typy poskytují vývojářům detailnější dokumentaci kódu a zjednodušují jeho čtení. + +3. Inteligentní doplňování kódu: + TypeScript poskytuje vývojářům nápovědu a automatickou dokončovací funkcionalitu. + +4. Lepší refaktorování: + Bezpečnější refaktorování díky statickým typům. + +5. Kompatibilita s existujícím JavaScriptem. + +6. Frameworky a knihovny: + TypeScript je dobře integrován s moderními frameworky jako React, Angular a Vue. + +## Základní datové typy + +**number:** +reprezentuje čísla, včetně celých čísel a desetinných čísel. + +```js +let count: number = 42; +``` + +**string:** +reprezentuje textové řetězce. + +```js +let message: string = "Hello, TypeScript!"; +``` + +**boolean:** +reprezentuje logické hodnoty true nebo false. + +```js +let isLogged: boolean = true; +``` + +**null a undefined:** +null a undefined jsou hodnoty, které reprezentují neexistující nebo neznámé hodnoty. + +```js +let data: null = null; +let value: undefined = undefined; +``` + +**object:** +reprezentuje jakýkoliv objekt. + +```js +let user: object = { + name: "John", + age: 30, +}; +``` + +**Array:** +reprezentuje pole hodnot určitého typu. + +```js +let numbers: number[] = [1, 2, 3, 4]; +let fruits: Array = ["apple", "banana", "orange"]; +``` + +**any:** +typ any umožňuje proměnným nabývat hodnot jakéhokoliv typu. Používejte s opatrností, protože ztrácíte typovou kontrolu. + +```js +let dynamicValue: any = "This can be anything."; +``` + +**void:** +reprezentuje absenci hodnoty. Používá se obvykle pro funkce, které nic nevracejí. + +```js +const logMessage = (): void => { + console.log("This is a log message."); +}; +``` + +**Promise:** +reprezentuje hodnotu, která bude k dispozici v budoucnosti, obvykle po dokončení asynchronní operace. Nejčastěji se používá při načítání dat z API. `` představuje typ dat nebo datovou strukturu, kterou funkce vrací. +```js +const myAsynFunction = async (url: string): Promise => { + const { data } = await fetch(url); + return data; +}; +``` + +### Interface + +Interface, případně se můžete setkat s českým označením rozhraní, slouží k definování struktury dat objektů, kdy se prostřednictvím interface určí jména a datové typy jejich vlastností. Používá se při definici props v komponentách a nebo při definování návratových hodnot funkcí. + +```js +interface Person { + name: string; + age: number; +}; +``` diff --git a/daweb/entry.yml b/daweb/entry.yml index 262d66cb..07f119c2 100644 --- a/daweb/entry.yml +++ b/daweb/entry.yml @@ -10,3 +10,4 @@ chapters: - js2 - react - velke-opakovani + - bonus