\section{Generikusok} \begin{frame}[fragile]{A probléma, amit a generikák oldanak meg} \footnotesize Képzeljünk el egy függvényt, ami egy tömb első elemét adja vissza -- de szeretnénk, hogy \emph{bármilyen} típusú tömbre működjön, miközben megőrizzük a típusinformációt. \begin{lstlisting}[language=JavaScript,style=NodeJS] function firstOfNumbers(arr: number[]): number { return arr[0]; } function firstOfStrings(arr: string[]): string { return arr[0]; } // ...es igy tovabb minden tipusra kulon fuggveny? \end{lstlisting} \begin{alertblock}{A probléma} \texttt{any}-jal megoldhatnánk, de akkor elveszítenénk a típusbiztonságot: a fordító többé nem tudná, mit ad vissza a függvény. \end{alertblock} \end{frame} \begin{frame}[fragile]{Generikus függvények} \footnotesize A \textbf{generikus típus} egy "típusparamétert" (jellemzően \texttt{T}) vezet be, amit a híváskor a konkrét típus tölt ki -- így egyetlen függvény működik bármilyen típusra, típusbiztonság elvesztése nélkül. \begin{lstlisting}[language=JavaScript,style=NodeJS] function first(arr: T[]): T { return arr[0]; } const n = first([1, 2, 3]); // T = number const s = first(['a', 'b', 'c']); // T = string \end{lstlisting} A TypeScript minden híváskor kikövetkezteti, mi legyen \texttt{T} -- a visszatérési érték típusa mindig pontosan illeszkedik a bemenethez. \end{frame} \begin{frame}[fragile]{Generikus interfészek} \footnotesize Nemcsak függvények, hanem interfészek (és típusok) is lehetnek generikusak -- ez az alapja például annak, ahogy a legtöbb adatbázis-eredmény vagy API válasz típus felépül. \begin{lstlisting}[language=JavaScript,style=NodeJS] interface Box { value: T; } const numberBox: Box = { value: 42 }; const stringBox: Box = { value: 'hello' }; interface ApiResponse { data: T; success: boolean; } \end{lstlisting} Egy \texttt{ApiResponse} pontosan jelzi, hogy a \texttt{data} mező egy \texttt{User} objektumot fog tartalmazni -- ezt fogjuk a későbbi heteken az Express válaszainknál is használni. \end{frame} \begin{frame}[fragile]{Constraints -- a generikus típus korlátozása} \footnotesize Néha nem szeretnénk \emph{bármilyen} típust elfogadni -- csak olyanokat, amiknek van egy adott mezőjük vagy tulajdonságuk. Erre valók a \texttt{extends} kulcsszóval megadott \textbf{constraint}-ek. \begin{lstlisting}[language=JavaScript,style=NodeJS] interface HasLength { length: number; } function logLength(item: T): T { console.log(item.length); return item; } logLength('hello'); // OK - a string-nek van length-je logLength([1, 2, 3]); // OK - a tombnek is logLength(42); // Hiba! a number-nek nincs length-je \end{lstlisting} \end{frame} \begin{frame}{Összefoglalás -- Generikus típusok} \footnotesize \begin{block}{Generikus típusok} \begin{itemize} \item A generikák elkerülik a kódduplikációt anélkül, hogy fel kellene adnunk a típusbiztonságot \item \texttt{function first(arr: T[]): T} -- a típusparamétert a hívás tölti ki \item Interfészek/típusok is lehetnek generikusak, pl. \texttt{Box}, \texttt{ApiResponse} \item \texttt{T extends ...} -- a generikus típus korlátozása egy adott "alakra" \end{itemize} \end{block} \end{frame}