English flagEnglish

5. gyakorlat - ES Modulok, TypeScript és React bevezető

2025-03-13 6 perc olvasási idő GitHub

Bevezetés

Ez a gyakorlat a modern JavaScript fejlesztési ökoszisztémát mutatja be három egymásra épülő lépésben:

  1. ES Modulok és npm (gyak5) – hogyan szervezzük modulokba a kódot és hogyan használjunk külső csomagokat
  2. TypeScript (gyak5_2) – statikus típusrendszer JavaScript felett
  3. 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
  • type aliast és interface-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 szintaxisconst x = require('./math')import x from './math.js'
Export szintaxismodule.exports = ...export default ... / export { ... }
Futási időSzinkron, dinamikusStatikus, fordítási időben elemzhető
Böngésző támogatásNem natívNatív (<script type="module">)
Aktiválásalapé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ípusSzintaxisMit importál?
Defaultimport valami from './math.js'A export default értékét
Namedimport { add } from './math.js'A export function add értékét
Named átnevezveimport { div as osztas } from './math.js'div → lokálisan osztas alatt érhető el
Mindenimport * 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

typeinterface
Objektumtípus
Örökléstype B = A & { ... } (intersection)interface B extends A { ... }
Primitív aliastype 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?

  1. document.getElementById('root') – megkeresi az index.html-ben lévő <div id="root"> elemet
  2. createRoot(...) – React gyökérpont létrehozása erre az elemre
  3. .render(...) – a React alkalmazást rendereli a <div>-be
  4. <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:

  1. TypeScriptből JavaScriptet generál
  2. JSX-ből React.createElement(...) hívásokat generál
  3. Modulokat összecsomagolja
  4. A böngésző csak a kész, optimalizált JavaScript-et látja

Összefoglalás

TémaKulcsfogalmak
ES Modulokexport default, export { }, import ... from, .js kiterjesztés kötelező
npmnpm install, node_modules, package.json "type": "module"
TypeScript – alaptípusokstring, number, boolean, : típus annotáció
TypeScript – objektumokInline típus, type alias, interface, ? opcionális, | union
TypeScript – függvényekParaméter és visszatérési érték típusa
React – komponensFüggvény, nagy betűs név, JSX visszatérési érték
React – propsSzülőtől érkező adatok, TypeScript-tel típusozva
Vitenpm 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.