it's largely a matter of coding style, and what you're used to.
i tend to coearce up-top on function if need be, along with assigning defaults to missing arguments.
this ensures that my variable's methods are present.
which can also be written as :
arg1= arg1 ? String(arg1) : "anon" ;
arg1= arg1 && String(arg1) || "anon" ;
if( ! (arg3 && arg3.join) ) arg3=[arg3];
on black box functions, i admit to using inline coercion operators to type cast. i know it's less-readable, but it's faster to execute (no function overhead) and less to type.
would turn my string vars into Numbers just-in-time for the addition operator.
var newAwesomeResult = +strFieldA + +strFieldB + +strFieldC;
would turn my numbered vars into Strings just-in-time for the concat operator.
var newAwesomeResult = numFieldA + ''+numFieldB + ''+numFieldC;
but, if there are more than two of something, i tend to jump to an array, which opens up a lot of options.
doing mathy stuff is the converse, you need numbers.
var newAwesomeResult = [ numFieldA, numFieldB, numFieldC ].join("");
var newAwesomeResult = [strFieldA, strFieldB, strFieldC].filter(Number).map(Number).reduce(sum);
It's trivial to filter/cast a whole array using String, Number, Boolean, and other native constructors. i find this lets me do stuff like add a fourth value into the sum calculation without re-writing the core logic. It also means i can code the summation core apart from the summation operation, re-using the sum() function in many places, resulting in more self-documenting, more-reusable, more -cachable, and more-debuggable code.
note that you can also use generics ascross types, even though not moany coders know about such magic.
for example, new String().match can be used on numbers:
this allows the handy methods that are locked into types (yuck) to be used freely (yay).
"".match.call(12345, //g) // == ["2", "4"]
you can use Function.bind() to pre-bake those generic applications (avoiding ".call(") into really fast callable functions:
so to me, weak types have a few limitations that if one can live with, one can code simply and elegantly. Even in the cases where you need a certain type, as we've seen, you don't really need a certain type. "Laziness" is just fine so long as your method signatures are defensive.
match(12345, /[2,4,6,8,0]/g) // == ["2", "4"]
Sounds like you need a dynamic code therapist to help you with your dirty feelings of compiler guilt. While i get what you are saying about things "feeling bad", that's hardly a scientific reason to indicate one system or the other. I suspect your emotional attachment has to do with prior punishments and rewards, as my own experiences, drawing mainly from JS, subtly steer me in a different direction.
in short, i think if you are going to go into a weak typed language, go all in.