How do you minimize chance of collision between system-named constraints on temp tables?
The easiest solution is to use a unique clustered index which does not have to be unique in the system (unlike a primary key constraint). Otherwise, they mostly function the same - a unique index is still a constraint that prevents duplicates and can also be used as the target of foreign keys.

I forget if this specific inline index syntax was possible in 2016 (I only have 2019 locally), but this works fine on newer versions:

CREATE TABLE #fooA(id int, INDEX PK1 UNIQUE clustered(id));
CREATE TABLE #fooB(id int, INDEX PK1 UNIQUE clustered(id));


If that syntax was not yet valid on 2016, you could create a unique clustered index in a second step, which you'd have to name yourself (but you wouldn't have to find some convoluted way to make that name unique).

Also, instead of over-using generic names like #TempTable, use names more specific to the table contents / procedure functionality (like #Orders, #Customers, etc). In cases where you need an explicit PK, this would at least reduce the chance of collisions if all of your PKs will no longer be system-named PK__#TempTab_....

As an aside, I don't think I've ever seen so many temp tables in a system that there are collisions on these long, tried-to-be-unique names. Are you trying to overwhelm the metadata?