TypeScript 01 · Základy TypeScriptu
Kam napsat typ (syntaxe TypeScriptu)
Kdy dvojtečka, kdy <…>, kdy nic. Anatomie zápisu, tahák situací a doplňovačka.
Načítám lekci…
TypeScript 01 · Základy TypeScriptu
Kdy dvojtečka, kdy <…>, kdy nic. Anatomie zápisu, tahák situací a doplňovačka.
Načítám lekci…
Když se stěhuješ, lepíš na krabice štítky: „kuchyň – sklo“, „knihy“, „zimní oblečení“. Krabicím samotným je štítek jedno – věci v nich jsou pořád stejné. Ale stěhováci podle štítků poznají, co se nesmí pokládat pod těžké knihy a kam co odnést. A až je všechno vybalené, štítky strhneš a vyhodíš.
TypeScript jsou štítky na JavaScriptu. Lepíš je na proměnné, parametry a vlastnosti: „tady je číslo“, „tady je uživatel nebo nic“. Kód díky nim nefunguje jinak – ale editor a kompilátor podle nich poznají, když se pokusíš dát sklo pod knihy (předat text tam, kde má být číslo). A při kompilaci se všechny štítky strhnou: prohlížeč dostane čistý JavaScript.
Tahle lekce není o tom, jaké štítky existují, ale kam se lepí: kdy dvojtečka, kdy <…> a kdy nic. Když to máš v malíku, typy v dalších lekcích už tě nezaskočí.
Na průhlednou krabici štítek nepotřebuješ – je vidět, co v ní je. Stejně tak TypeScript u const count = 0 vidí nulu a sám ví, že jde o číslo. Tomu se říká odvození typu (inference). Štítek musíš nalepit tam, kde dovnitř vidět není: na prázdnou krabici (prázdné pole), na krabici, která zatím zeje prázdnotou (null), nebo na krabici, která teprve přijede (parametr funkce, data z API).
Druhá věc, kterou je dobré vědět: typy po kompilaci zmizí – štítky se strhnou. Když z kódu mentálně vymažeš všechny typy, musí zbýt platný JavaScript. To je nejlepší test, jestli je typ na správném místě.
Zkusme to na typické funkci:
function formatPrice(amount: number, currency?: string): string {return amount + ' ' + (currency ?? 'Kč')}
amount: number – parametr amount je typu číslo. Název, dvojtečka, typ.currency?: string – otazník patří k názvu: parametr je nepovinný. Uvnitř funkce může být undefined, proto ?? 'Kč'.): string – dvojtečka za závorkou s parametry je typ toho, co funkce vrací. Stejné pravidlo, jen „název“ je tentokrát celé volání funkce.Teď štítky strhneme:
function formatPrice(amount, currency) {return amount + ' ' + (currency ?? 'Kč')}
Zbyl platný JavaScript. Kdyby ne – třeba kdyby z ({ title: string }) zbylo něco, co dělá jinou věc – typ byl na špatném místě. K tomu se dostaneme v další kapitole.
Co vidíš: Několik typických řádků s typy. Každý kousek je obarvený: fialově typ, oranžově syntaxe TypeScriptu (dvojtečky, otazníky, závorky), normálně obyčejný JavaScript. Podtržené kousky mají vysvětlivku.
Vyzkoušej:
price, dvojtečku a number. Pod kódem se objeví, co který kousek znamená.Co z toho plyne: Typ je vždy štítek nalepený na konkrétní místo, nejčastěji za dvojtečku. Bez něj zůstane JavaScript, který dělá totéž.
Načítám interaktivní část…
Dvojtečka je v JavaScriptu i bez TypeScriptu – v objektech odděluje klíč a hodnotu, v destrukturaci přejmenovává. Proto je to nejčastější zdroj zmatku: stejný znak, tři různé významy. Pomáhá se zeptat: stojí dvojtečka za něčím, co právě deklaruju? Pak je to štítek.
| Místo | Zápis | Poznámka |
|---|---|---|
| Proměnná | let name: string | Jen když TS typ neodvodí z hodnoty. |
| Parametr | (name: string) => … | Vždy. |
| Nepovinný parametr / vlastnost | name?: string | Otazník patří k názvu. |
| Návratová hodnota | function f(): string | Za ), u arrow funkce před =>. |
| Vlastnost v interface / type | { name: string } | Popis tvaru objektu. |
| Props komponenty | ({ name }: Props) | Za celou destrukturaci! |
| Tady dvojtečka NENÍ | Zápis | Proč |
|---|---|---|
| Definice type | type Id = string | number | Pojmenováváš typ → rovnítko. |
| Definice interface | interface User { … } | Klíčové slovo + jméno + tělo. |
| Typ pro funkci/hook | useState<User | null>(null) | Typ se funkci PŘEDÁVÁ ve špičatých závorkách. |
| Objekt s hodnotami | { name: 'Jana' } | Tady dvojtečka odděluje klíč a HODNOTU. |
| JSX | <Card title="Ahoj" /> | V JSX žádné typy – TS je kontroluje podle props. |
| Destrukturace | { title: nadpis } | Dvojtečka tu znamená PŘEJMENOVÁNÍ proměnné. |
Zpátky ke krabicím. Štítek lepíš tam, kam není vidět, a na krabice, které přijíždějí zvenku. Na průhlednou krabici ho nelepíš – jen bys přidal práci a riziko, že štítek nebude odpovídat obsahu.
// Průhledné krabice – TS vidí dovnitř, štítek nepišconst count = 0 // numberconst names = ['Jana', 'Petr'] // string[]const [open, setOpen] = useState(false) // boolean// Krabice přijíždějí zvenku – štítek piš vždyfunction greet(name: string) { … } // parametr: kdo ví, co sem kdo pošleinterface CardProps { title: string } // props: totéž pro komponenty// Neprůhledné krabice – TS nevidí dovnitř, štítek dopišconst [user, setUser] = useState<User | null>(null) // teď null, později Userconst [todos, setTodos] = useState<Todo[]>([]) // prázdné pole – prvky čeho?
Jednoduché pravidlo: typy piš na hranicích – kde data vstupují (parametry, props, API) nebo kde TS nemá z čeho typ poznat. Uvnitř funkcí ho nech pracovat.
| ✅ Piš vždy | 🤔 Piš, když TS neodvodí | 🚫 Nepiš (zbytečné) |
|---|---|---|
| Parametry funkcí | useState<User | null>(null) | const x: number = 5 |
| Props komponent (interface) | useState<Todo[]>([]) | useState<number>(0) |
| Tvary dat (interface User) | const data: User = await res.json() | Parametry inline handlerů v JSX |
| Data z API (JSON) | Samostatné event handlery | Parametry callbacků (.map(item => …)) |
| Veřejné funkce knihovny / utils | [object Object]přiřazení později | Návratový typ jednoduchých funkcí |
Tahák pro situace, které potkáš nejčastěji. Používej ho jako kuchařku: najdi, co právě píšeš, a podívej se, kam štítek patří.
Co vidíš: Tlačítka s typickými situacemi, rozdělená na obyčejný JavaScript a React. Ke každé situaci je správný zápis, nejčastější chyba a krátké vysvětlení.
Vyzkoušej:
{ title: string } uvnitř závorek – za chvíli ji uvidíš i v kvízu.Co z toho plyne: Většina situací se opakuje. Až si je párkrát najdeš v taháku, začneš štítky psát na správná místa automaticky.
Načítám interaktivní část…
| Symbol | Příklad | Význam |
|---|---|---|
: | age: number | „je typu“ |
? | age?: number | nepovinné (může chybět / být undefined) |
| | string | null | „nebo“ – union |
& | A & B | „a zároveň“ – spojení typů |
[] | string[] | pole |
[A, B] | [string, number] | tuple – pole s pevnou délkou |
=> | (id: number) => void | typ funkce |
<T> | Array<User> | generikum – typ jako parametr |
as | data as User | „věř mi“ – přetypování bez kontroly (šetři s ním) |
as const | ['a', 'b'] as const | nejpřesnější možný (readonly) typ |
! | ref.current! | „určitě není null“ – bez kontroly |
typeof | typeof config | typ z existující hodnoty |
keyof | keyof User | union názvů vlastností: "name" | "age" |
ChangeEvent) skočí na jeho definici.any nabídne „Infer parameter types from usage“.Doplň do políček, co tam patří – typ, symbol, nebo nic. Každé cvičení trénuje jedno místo, kam se štítek lepí. Pamatuj na průhledné krabice: někdy je správná odpověď nechat políčko prázdné.
function double(n) {
return n * 2
}function greet(name: string) {
return 'Ahoj ' + name
}function greet(name: string, excited boolean) {
return excited ? name + '!' : name
}interface User {
name string
age number // nepovinné
}interface User { name: string }
const jana: User = { name: }type Status 'idle' | 'loading' | 'error'
interface AvatarProps {
src: string
size?: number
}
function Avatar({ src, size = 40 }) {
return <img src={src} width={size} />
}interface ListProps {
items: string[]
onSelect: // dostane index vybrané položky
}const [user, setUser] = useState(null)
const [todos, setTodos] = useState([])
const [count, setCount] = useState(0)
let selected = null // později: selected = jana (jana je User)
const handleChange = (e) => {
setName(e.target.value)
}async function loadUser(id: number): {
const res = await fetch('/api/users/' + id)
return res.json()
}function first(items: T[]): T | undefined {
return items[0]
}function minMax(nums: number[]) {
return [Math.min(...nums), Math.max(...nums)]
}function Badge({ label: string, color: string }) {return <span style={{ color }}>{label}</span>}
setItems([...items, 'nový']) hlásí chybu?const [items, setItems] = useState([])
// Aconst handleClick: (e: MouseEvent<HTMLButtonElement>) => void = (e) => { … }// Bconst handleClick = (e: MouseEvent<HTMLButtonElement>) => { … }// Cconst handleClick = (e) : MouseEvent<HTMLButtonElement> => { … }
const Card = ({ title }) => <h2>{title}</h2>
Vyměň dvakrát any za skutečný typ a doplň, co funkce vracejí.
Zadání najdeš v komentářích v kódu níže – na začátku souboru a u míst označených TODO.
Načítám interaktivní část…
V obou výzvách je hotový kód plný any – krabic bez štítků. Tvým úkolem je štítky nalepit na správná místa: nejdřív u obyčejných funkcí, pak v React komponentě. Na stránce se nic nezmění; rozdíl uvidí jen TypeScript.
Sedm malých funkcí, sedm míst, kam typ patří. Výstup na stránce se nezmění – rozdíl uvidí jen TypeScript. Jaké typy kam patří, je v komentářích v kódu.
Zadání najdeš v komentářích v kódu níže – na začátku souboru a u míst označených TODO.
Načítám interaktivní část…
Typická místa v React komponentě: props, callback, useState a event handler. Co kde má být za typ, je v komentářích v kódu.
Střední a těžké výzvy se odemknou, jakmile se přihlásíš. Stejně jako celý kurz jsou zdarma – stačí e-mail, žádné heslo ani platba.
function f(): T.({ a, b }: Props). Uvnitř { } dvojtečka přejmenovává!type X = … (rovnítko), interface X { … }, typ pro hook ve špičatých závorkách: useState<T>().null, prázdná pole); průhledné krabice nech TS odvodit.products)products – ze souboru src/course/fakeApi.ts. Falešné API kurzu: data a funkce, které předstírají server (se zpožděním, občas i s chybou). Ve skutečné aplikaci by tu bylo volání fetch().export interface Product {id: numbername: stringcategory: 'ovoce' | 'zelenina' | 'pečivo' | 'mléčné'price: numberinStock: boolean}export const products: Product[] = [{ id: 1, name: 'Jablko', category: 'ovoce', price: 12, inStock: true },{ id: 2, name: 'Banán', category: 'ovoce', price: 8, inStock: true },{ id: 3, name: 'Hruška', category: 'ovoce', price: 15, inStock: false },{ id: 4, name: 'Mrkev', category: 'zelenina', price: 6, inStock: true },{ id: 5, name: 'Rajče', category: 'zelenina', price: 9, inStock: true },{ id: 6, name: 'Okurka', category: 'zelenina', price: 19, inStock: false },{ id: 7, name: 'Rohlík', category: 'pečivo', price: 3, inStock: true },{ id: 8, name: 'Chléb', category: 'pečivo', price: 45, inStock: true },{ id: 9, name: 'Mléko', category: 'mléčné', price: 22, inStock: true },{ id: 10, name: 'Sýr eidam', category: 'mléčné', price: 39, inStock: true },{ id: 11, name: 'Jogurt', category: 'mléčné', price: 14, inStock: false },{ id: 12, name: 'Pomeranč', category: 'ovoce', price: 11, inStock: true },]
row, stack, card, list, btn, input nebo muted jsou hotové styly kurzu v src/styles.css (row = prvky vedle sebe, stack = pod sebou, card = rámeček, muted = šedý text).