If you say just a bare:
console.log(s) if s?
then you will indeed get the JavaScript you're expecting (demo):
if (typeof s !== "undefined" && s !== null) {
console.log(s);
}
However, if s is a known variable such as here:
f = (s) -> console.log(s) if s?
then you'll get (demo):
if (s != null) {
//...
}
for the s? test.
So why the difference? In the first case, CoffeeScript cannot guarantee that there is an s variable in existence anywhere so it must do a typeof s check in order to avoid a ReferenceError exception.
However, if s is known to exist because it is a function parameter or has been assigned to as a local variable (so that CoffeeScript will produce a var s), then you don't need the typeof s check since you cannot, in this case, get a ReferenceError.
That leaves us with s !== null versus s != null. Dropping down to non-strict inequality (s != null) allows you to check if s is undefined or null with a single comparison. When you check typeof s !== "undefined", you wrapping the undefined test in with the "is there an s variable" check and a strict s !== null test is all that you need to check for null.