Consider the simply-typed lambda calculus over some set of base types, with call-by-value evaluation semantics. (Exactly what is discussed in Types and Programming Languages, in case it matters -- I'm not sure whether other books define it differently). We want to show that evaluation of any well-typed term halts after finitely many steps.
I have an idea for a proof which I find much easier to understand than the standard "logical relations" one, and I am wondering if it's correct. I'm a bit doubtful because if it is correct, why can't I find it online or in textbooks?
Let $t: T$ be a well-typed term, and consider the collection of sizes of types of arguments of lambda expressions appearing anywhere in $t$. The notion of "size" can be whatever you like, as long as $T\to S$ has greater size than either $T$ or $S$, and sizes are nonnegative integers. For concreteness, let's use "number of arrows in the type's written representation".
For example, if $A$ is a base type, $a_0:A$ some constant, and $$t = \left(\lambda f:(A\to A)\to A.\lambda g:A\to A. f\,g\right)(\lambda h:A\to A. a_0)(\lambda a:A.a_0)$$
then the sizes of interest to us are 2, 1, 1, and 0.
We show that if $t\to t'$, where $t$ is well-typed, then some lambda abstraction whose argument's type is of size $k$ will disappear and be replaced with zero or more lambda abstractions whose arguments' types are of sizes strictly less than $k$.
The result then follows from the obvious fact that the operation of repeatedly removing some element $k$ from a finite list of non-negative integers and then adding zero or more non-negative integers smaller than $k$ cannot be performed infinitely many times. (If anyone is not convinced of this, I can prove it in the comments).
We proceed by induction on the structure of $t$. If $t$ is a value, then $t\not \to t'$, contradicting our assumption. If $t = s_1 s_2$ where neither $s_1$ nor $s_2$ is a value, then for some $s_1'$ with $s_1 \to s_1'$, $t' = s_1' s_2$, and the claim is true by induction. Similarly if $t = v s$ for a value $v$ and non-value $s$.
The last remaining case is $t = v_1 v_2$ where $v_1$ and $v_2$ are values. Then there must be some types $T_1$ and $T_2$ such that $v_2: T_2$ and $v_1: T_2\to T_1$. Then $v_1$ must have the form $\lambda x:T_2.s_1$ for some term $s$.
If $T_2$ is a base type, clearly substituting $x$ by $v_2$ in $v_1$ cannot violate our condition, since it destroys $v_1$ without creating any new lambda abstractions. Otherwise, $T_2$ must have the form $S_1\to S_2$, and $v_2$ the form $\lambda y:S_1.s_2$. Then substituting $v_2$ into $v_1$ might create many new copies of $v_2$, i.e., lambda expressions whose arguments have type $S_1$. But it gets rid of $v_1$, a lambda expression whose type is $T_2=S_1\to S_2$, which is larger than $S_1$, and again our condition is preserved.