As suggested by my comment, here's a mathematical solution that works like \pgfpointcurveattime and \pgftransformcurveattime but with …atangle.
For TikZ, I'm using pos angle = <angle> that switches out the curve timer for the curve angle timer.
The core of this answer is \pgfpointcurveatangle@ which will “return” the time t as \@time which then will be forwarded by the …curveatangles to the …curveattimes. (This technically does do work twice because the …curveattimes also return the angle for the use with sloped.)
Instead of PGFMath, I'm using \fpeval since I've run into problems with basic PGFmath.
This probably can be converted so that it uses the fpu library but I don't have much experience with it.
Using pos angle with any other path than an explicit Bézier should do nothing. “Explicit” means that it will only work with .. controls or the various out/in options.
While arcs are drawn as Bézier curves on the lowest level, they use a different timer and won't handle the angle timer.
Lastly, I've added a node to show what PGF thinks the angle of the tangent is which, expectedly, is a bit off.
To use it, just place a coordinate, node or pic along a curve and instead of pos (or its implicit versions like midway) use pos angle. If you want the node or pic also angled use sloped and possibly allow upside down.
In your case, I've added a pic called cs which just places three coordinates named <name>, <name>-x and <name>-y (where <name> is the name of the pic). The pic cs style can then be used to shift and rotate the coordinate system as if you were drawing in the pic.
Then you can draw your tangent as such:
\draw[blue] (0,5) to[out=-5,in=100]
pic[pos angle=-30, sloped] (a) {cs} (8,0);
\draw[pic cs=a, red] (-2,0) -- (2,0);
\draw (a) circle[radius=3pt];
Don't forget allow upside down otherwise your cs might be rotated.
With
pics/cs/.prefix style={/tikz/allow upside down, /tikz/sloped}
you can make every cs pic automatically sloped and upside down.
Code
\documentclass[tikz,convert]{standalone}
\makeatletter
%% Utils
\def\pgfextractxy#1{\pgf@process{#1}\pgfgetlastxy}
\newcommand*\fpUnlessIf[1]{
\edef\pgfmathresult{\fpeval{#1}}%
\ifnum\pgfmathresult=1 \expandafter\@gobble
\else\expandafter\@firstofone\fi}
\newcommand*\fpsetmacro[2]{\edef#1{\fpeval{#2}}\typeout{#1 = #2}}
%% PGF
\def\pgfpointcurveatangle@#1#2#3#4#5{%
\def\@time{1}\fpsetmacro\@tan{tand(#1)}%
\pgfextractxy{#2}\@Ax\@Ay \pgfextractxy{#3}\@Bx\@By
\pgfextractxy{#4}\@Cx\@Cy \pgfextractxy{#5}\@Dx\@Dy
\fpsetmacro\@divisor{
-3*\@Bx*\@tan+3*\@Cx*\@tan-\@Dx*\@tan-\@Ax*\@tan -\@Ay+3*\@By-3*\@Cy+\@Dy}%
\fpUnlessIf{\@divisor==0}{% divide by 0?
\fpsetmacro\@divnosqrt{%% calculate dividend (no sqrt part)
-2*\@Bx*\@tan+\@Cx*\@tan+\@Ax*\@tan-\@Ay+2*\@By-\@Cy}%
\fpsetmacro\@divsqrt{%% calculate divident (sqrt part)
(-4*\@Bx*\@tan+2*\@Cx*\@tan+2*\@Ax*\@tan -2*\@Ay+4*\@By-2*\@Cy)^2
-4*(\@Bx*\@tan-\@Ax*\@tan+\@Ay-\@By)
*(3*\@Bx*\@tan-3*\@Cx*\@tan+\@Dx*\@tan-\@Ax*\@tan+\@Ay-3*\@By+3*\@Cy-\@Dy)}%
\fpUnlessIf{\@divsqrt<0}{% sqrt(neg)?
\fpsetmacro\@time{(.5*sqrt(\@divsqrt)+\@divnosqrt)/\@divisor}%
\fpUnlessIf{\@time>=0&&\@time<=1}{%
\fpsetmacro\@time{(-.5*sqrt(\@divsqrt)+\@divnosqrt)/\@divisor}}%
}}}
\def\pgfpointcurveatangle#1#2#3#4#5{%
\pgfpointcurveatangle@{#1}{#2}{#3}{#4}{#5}%
\pgfpointcurveattime{\@time}{#2}{#3}{#4}{#5}}
\def\pgftransformcurveatangle#1#2#3#4#5{%
\pgfpointcurveatangle@{#1}{#2}{#3}{#4}{#5}%
\pgftransformcurveattime{\@time}{#2}{#3}{#4}{#5}}
% TikZ
\newif\iftikz@angletimer
\def\tikz@timer@curve{%
\iftikz@angletimer
\pgftransformcurveatangle{\tikz@time@angle}{\tikz@timer@start}
{\tikz@timer@cont@one}{\tikz@timer@cont@two}{\tikz@timer@end}%
\else
\pgftransformcurveattime{\tikz@time}{\tikz@timer@start}
{\tikz@timer@cont@one}{\tikz@timer@cont@two}{\tikz@timer@end}%
\fi}%
\tikzset{
pos angle/.code=%
\edef\tikz@time@angle{#1}%
\ifx\tikz@time@angle\pgfutil@empty\else
\pgfmathsetmacro\tikz@time@angle{\tikz@time@angle}\fi
\tikz@angletimertrue,
pos/.append code=\tikz@angletimerfalse}
\makeatother
\usetikzlibrary{calc}
\tikzset{
cs/.pic={
\coordinate (-x) at (1,0) coordinate (-y) at (0,1) coordinate () at (0,0);},
pic cs/.style={shift={(#1)}, x={($(#1-x)-(#1)$)}, y={($(#1-y)-(#1)$)}}}
\begin{document}
\begin{tikzpicture}
\draw (0,6) -- (0,0) -- (9,0);
\draw[blue] (0,5) to[out=-5,in=100]
pic[pos angle=-30, sloped] (a) {cs} (8,0);
\draw[pic cs=a, red] (-2,0) -- (2,0);
\draw (a) circle[radius=3pt];
\node[below left] at (a) {
\pgfmathanglebetweenpoints{\pgfpointanchor{a}{center}}
{\pgfpointanchor{a-x}{center}}
\pgfmathresult};
\end{tikzpicture}
\end{document}
Output

0,.05, …,.95,.1and choose the one that's closest to the desired angle. It gets even more interesting when you're not looking at only one Bézier curve but a path comprised out of multiple segments. – Qrrbrbirlbel Jan 11 '23 at 14:36