5. gyakorlat - ES Modulok, TypeScript és React bevezető
Bevezetés
Ez a gyakorlat a modern JavaScript fejlesztési ökoszisztémát mutatja be három egymásra épülő lépésben:
- ES Modulok és npm (
gyak5) – hogyan szervezzük modulokba a kódot és hogyan használjunk külső csomagokat - TypeScript (
gyak5_2) – statikus típusrendszer JavaScript felett - React + Vite (
gyak5_3) – komponens-alapú UI keretrendszer, projekt- és build-eszközzel
A mai óra után képes leszel:
- Named és default exportokat/importokat helyesen használni
- Node.js projektben npm csomagot telepíteni és beimportálni
- Alapvető TypeScript típusannotációkat írni változókhoz, objektumokhoz és függvényekhez
typealiast ésinterface-t definiálni- Vite segítségével React-projektet indítani és egyszerű komponenst készíteni
1. rész – ES Modulok és npm (gyak5)
Projekt struktúra
gyak5/
├── package.json # npm konfiguráció (type: "module" – fontos!)
├── index.js # belépési pont
└── math.js # saját modul
type: "module" a package.json-ban
{
"name": "gyak5",
"type": "module",
"dependencies": {
"cowsay": "^1.6.0"
}
}
A "type": "module" beállítás azt mondja meg a Node.js-nek, hogy a projekt .js fájljai ES Module szintaxissal íródnak. Enélkül a Node.js minden .js fájlt régi CommonJS (CJS) modulként kezelne.
| CommonJS (régi) | ES Module (modern) | |
|---|---|---|
| Import szintaxis | const x = require('./math') | import x from './math.js' |
| Export szintaxis | module.exports = ... | export default ... / export { ... } |
| Futási idő | Szinkron, dinamikus | Statikus, fordítási időben elemzhető |
| Böngésző támogatás | Nem natív | Natív (<script type="module">) |
| Aktiválás | alapértelmezett | "type": "module" a package.json-ban |
A böngészőben már az 1. gyakorlat óta type="module" attribútummal töltöttük be a scriptjeinket. Most Node.js oldalon is ugyanez a rendszer érvényes – ezért kell a package.json-ba a "type": "module".
1. feladat: Saját modul készítése – math.js
A math.js fájl aritmetikai segédfüggvényeket tartalmaz, amelyeket más fájlokból is el akarunk érni.
// math.js
export function add(a, b) {
return a + b;
}
function mul(a, b) {
return a * b;
}
function div(a, b) {
if (b == 0) {
return 0;
}
return a / b;
}
export {
mul,
div
}
export default add;
Named export vs Default export
Egy modulnak egy default exportja lehet, de bármennyi named exportja.
// Named export – névvel exportálunk
export function mul(a, b) { ... }
export { div }
// Default export – "névtelen" export, amit importáláskor bárminek nevezhetünk
export default add;
2. feladat: Import szintaxisok – index.js
// index.js
import cowsay from 'cowsay';
import alma, { div as osztas, mul } from './math.js';
Az import sor részei
import alma, { div as osztas, mul } from './math.js';
// ^^^^ ^^^^^^^^^^^^^^^^^^^
// │ named exportok (div átnevezve osztas-ra, mul változatlanul)
// │
// default export (bármilyen névvel behívható, itt: alma)
| Import típus | Szintaxis | Mit importál? |
|---|---|---|
| Default | import valami from './math.js' | A export default értékét |
| Named | import { add } from './math.js' | A export function add értékét |
| Named átnevezve | import { div as osztas } from './math.js' | div → lokálisan osztas alatt érhető el |
| Minden | import * as Math from './math.js' | Egy objektumba csomagolja az összes named exportot |
Node.js ES Module módban a relatív importoknál kötelező a fájlkiterjesztés: './math.js', nem './math'. A böngészőben ugyanez a szabály. TypeScript esetén .ts helyett is .js-t kell írni az importban (a fordító kezeli).
3. feladat: Külső npm csomag telepítése
npm install cowsay
Ez hozzáadja a cowsay csomagot a node_modules/ mappába és rögzíti a package.json dependencies szekciójában.
import cowsay from 'cowsay';
const message = cowsay.say({
text: "Nem szeretem a pénteki órákat"
});
console.log(message);
A futtatás:
node index.js
Külső csomagoknál (cowsay) nincs szükség relatív útvonalra vagy .js-re. A Node.js a node_modules/ mappából keresi meg automatikusan. Saját fájloknál mindig relatív útvonalat kell használni (./math.js).
2. rész – TypeScript (gyak5_2)
Mi a TypeScript?
A TypeScript a JavaScript egy statikusan típusos szuperhalmaza: minden érvényes JavaScript egyben érvényes TypeScript is, de TypeScript kódon felül típusinformációkat is írhatunk.
JavaScript ⊂ TypeScript
A TypeScript nem fut közvetlenül böngészőben vagy Node.js-ben. Előbb le kell fordítani JavaScriptre a TypeScript fordítóval (tsc):
npx tsc index.ts
Ez egy index.js fájlt generál – a böngésző vagy Node.js csak ezt látja.
Projekt struktúra
gyak5_2/
├── package.json # devDependencies: typescript
├── tsconfig.json # fordítási konfiguráció
└── src/
└── index.ts # TypeScript forrásfájl
1. feladat: Változók és alaptípusok annotálása
let name = "Valaki"; // TypeScript kikövetkezteti: string
let age: number; // Explicit típusannotáció
age = 12;
Ha nem adjuk meg a típust, TypeScript megpróbálja kikövetkeztetni (type inference) az értékből. Explicit annotáció csak akkor szükséges, ha a változó nem kap kezdőértéket, vagy ha a kikövetkeztetett típust pontosítani akarjuk.
let age: number; // Nincs kezdőérték → manuális annotáció szükséges
age = "hello"; // ❌ Fordítási hiba: 'string' nem rendelhető 'number'-hoz
age = 25; // ✅ OK
2. feladat: Objektumok típusannotálása
Inline objektumtípus
let person: { name: string, age: number, height?: number, weight: number | undefined };
person = {
name: "Valaki",
age: 20,
weight: undefined
// height: 170 – elhagyható, mert '?' jelöli az opcionális mezőt
};
A kulcsszavak:
?– opcionális mező: az objektum létrehozásakor elhagyható (height?)|– union típus: a mező értéke több típus egyike lehet (number | undefined)
Opcionális (?) vs | undefined
type Example = {
a?: number; // a nem kötelező; ha megadják, number kell
b: number | undefined; // b kötelező, de értéke undefined is lehet
}
// a?: number
const o1: Example = {}; // ✅ – a elhagyható
const o2: Example = { b: undefined }; // ✅ – b jelen van, de undefined
// b: number | undefined esetén b-t meg kell adni az objektumban
const o3: Example = { a: 5 }; // ❌ – b hiányzik
3. feladat: type alias
A type kulcsszóval újrafelhasználható típusnevet hozhatunk létre:
type User = {
username: string;
email: string;
password?: string;
}
const admin: User = {
username: "admin",
email: "admin@elte.hu"
// password nem kötelező
};
4. feladat: interface és öröklés
interface Animal {
name: "Cat" | "Dog" | "Tiger"; // Literal union típus: csak ez a három string lehet
}
interface WildAnimal extends Animal {
country: "Asia" | "Africa";
}
const tiger: WildAnimal = {
name: "Tiger",
country: "Asia"
};
type vs interface
type | interface | |
|---|---|---|
| Objektumtípus | ✅ | ✅ |
| Öröklés | type B = A & { ... } (intersection) | interface B extends A { ... } |
| Primitív alias | ✅ type ID = string | ❌ |
| Declaration merging | ❌ | ✅ (azonos névvel bővíthető) |
| Osztályok implementálják | ✅ | ✅ |
A legtöbb esetben felcserélhető a kettő. Konvenció: objektumstruktúrákhoz és osztálykontraktushoz interface, minden máshoz (union, alias, tuple) type.
5. feladat: Függvények típusannotálása
function add(a: number, b: number): number {
return a + b;
}
function div(a: number, b: number): number | undefined {
if (b === 0) {
return undefined;
}
return a / b;
}
A visszatérési típus : number a paraméterlista után áll. Ha a függvény hibás esetben nem tud számot visszaadni, a visszatérési típus number | undefined.
const result = div(10, 0);
// TypeScript tudja, hogy result: number | undefined
// Ezért kényszert: használat előtt ellenőrizni kell!
if (result !== undefined) {
console.log(result * 2); // ✅
}
Ez az egyik legfontosabb előnye a TypeScriptnek: a fordító kényszeríti a hibakezelést, nem hagyja figyelmen kívül az undefined lehetőségét.
3. rész – React + Vite (gyak5_3)
Mi a Vite?
A Vite egy modern build és fejlesztői eszköz. Helyettesíti a kézi HTML/script elrendezést:
- Fejlesztés közben villámgyors szerver (
npm run dev) - Produkciós build: optimalizált JS/CSS bundle (
npm run build) - Pluginrendszer: React, TypeScript és más eszközök beépített támogatása
npm run dev # fejlesztői szerver, HMR (Hot Module Replacement)
npm run build # produkciós bundle generálása
Projekt struktúra
gyak5_3/
├── package.json
├── vite.config.ts
├── index.html # Belépési pont – egyetlen <div id="root">
└── src/
├── main.tsx # React fa mountolása
├── App.tsx # Gyökérkomponens
├── Hello.tsx # Saját komponens
└── index.css
1. feladat: A React alkalmazás mountolása – main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
Mi történik itt?
document.getElementById('root')– megkeresi azindex.html-ben lévő<div id="root">elemetcreateRoot(...)– React gyökérpont létrehozása erre az elemre.render(...)– a React alkalmazást rendereli a<div>-be<StrictMode>– fejlesztési módban extra ellenőrzések (kettős renderelés a mellékhatások feltárásához)
A ! az getElementById végén TypeScript non-null assertion: azt mondja a fordítónak, hogy biztosan nem null az érték. Ha a #root elem hiányzik az HTML-ből, futásidejű hiba keletkezne.
2. feladat: Komponensek – App.tsx és Hello.tsx
Mi a JSX?
A .tsx fájlban HTML-szerű szintaxist írhatunk JavaScript kódba ágyazva. Ezt JSX-nek hívják:
function App() {
return (
<div>
<h1>Hello world</h1>
<Hello name="Felhasználó" />
</div>
);
}
Ez valójában nem HTML, hanem szintaktikai cukor. A build folyamat az alábbivá fordítja:
React.createElement("div", null,
React.createElement("h1", null, "Hello world"),
React.createElement(Hello, { name: "Felhasználó" })
)
A JSX olvashatóbb, a kettő viszont teljesen egyenértékű.
Komponens definíció
// Hello.tsx
export function Hello({ name }: { name: string }) {
return <p>Hello {name}!</p>;
}
Egy React komponens:
- Sima JavaScript/TypeScript függvény, amely JSX-et ad vissza
- Neve nagy betűvel kezdődik (különben a React natív HTML tagként kezeli)
- Props-on (paramétereken) keresztül kap adatot a szülőjétől
Props TypeScript-tel
// A props típusa inline, destructuringgal
export function Hello({ name }: { name: string }) {
return <p>Hello {name}!</p>;
}
// Alternatíva: type alias
type HelloProps = {
name: string;
};
export function Hello({ name }: HelloProps) {
return <p>Hello {name}!</p>;
}
A { name } a props objektum destrukturálása: a prop-ok egyetlen objektumként érkeznek, és a TypeScript ellenőrzi, hogy mindenki a helyes típusú értéket ad-e át.
Komponens használata
// App.tsx
import { Hello } from "./Hello";
function App() {
return (
<div>
<h1>Hello world</h1>
<Hello name="Felhasználó" />
</div>
);
}
export default App;
Az import { Hello } named importot használ – ez megfelel az export function Hello deklarációnak.
A build folyamat összefoglalása
src/main.tsx → Vite (TypeScript + JSX fordítás) → JavaScript bundle
↓
index.html <script>
↓
Böngésző futtatja
A fejlesztő .tsx / .ts fájlokat ír. A Vite:
- TypeScriptből JavaScriptet generál
- JSX-ből
React.createElement(...)hívásokat generál - Modulokat összecsomagolja
- A böngésző csak a kész, optimalizált JavaScript-et látja
Összefoglalás
| Téma | Kulcsfogalmak |
|---|---|
| ES Modulok | export default, export { }, import ... from, .js kiterjesztés kötelező |
| npm | npm install, node_modules, package.json "type": "module" |
| TypeScript – alaptípusok | string, number, boolean, : típus annotáció |
| TypeScript – objektumok | Inline típus, type alias, interface, ? opcionális, | union |
| TypeScript – függvények | Paraméter és visszatérési érték típusa |
| React – komponens | Függvény, nagy betűs név, JSX visszatérési érték |
| React – props | Szülőtől érkező adatok, TypeScript-tel típusozva |
| Vite | npm run dev, npm run build, .tsx → .js fordítás |
Miért ez a sorrend?
A három technológia egymásra épül:
ES Modules → TypeScript → React
(kódszervezés) (típusbiztonság) (UI komponensek)
React TypeScript nélkül is használható, TypeScript viszont sokkal könnyebbé teszi a React fejlesztést – az IDE onnantól tudja, milyen prop-okat vár egy komponens, és hibát jelez, ha valami hiányzik.