90 lines
3.3 KiB
TeX
90 lines
3.3 KiB
TeX
\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<T>(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<T> {
|
|
value: T;
|
|
}
|
|
|
|
const numberBox: Box<number> = { value: 42 };
|
|
const stringBox: Box<string> = { value: 'hello' };
|
|
|
|
interface ApiResponse<T> {
|
|
data: T;
|
|
success: boolean;
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Egy \texttt{ApiResponse<User>} 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<T extends HasLength>(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<T>(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<T>}, \texttt{ApiResponse<T>}
|
|
\item \texttt{T extends ...} -- a generikus típus korlátozása egy adott "alakra"
|
|
\end{itemize}
|
|
\end{block}
|
|
\end{frame}
|