easyJS ES5#124

Es letra (is single letter)

Prompt

Return true if a given string is a single ASCII letter (a-z or A-Z), false for numbers, symbols, or longer strings.

Solution

function isLetter(char) {
  return typeof char === 'string' && char.length === 1 && /[a-zA-Z]/.test(char)
}
Mentor's take

Trivial-looking validation questions test one thing: whether you write predicates that are safe on hostile input, not just wrong input. This is defensive type-checking as a guard chain, ordered so each check makes the next one safe: typeof first (so .length can't throw on null or a number), length second (so the regex verdict applies to the whole value), character class last. All O(1).

The subtle regex trap is why the length check can't be skipped: an unanchored /[a-zA-Z]/.test(s) asks "does s contain a letter anywhere", so "ab", "1a", and "hello!" all pass it. Two correct fixes: check length === 1 separately (as here), or anchor the pattern — /^[a-zA-Z]$/. Knowing that test searches rather than matches-whole is a small fact that kills a whole family of validation bugs, including real-world input sanitizers.

Also worth saying: typeof char === 'string' makes the function total — it returns false for 5, null, undefined, or an object rather than throwing mid-expression. A predicate that can throw isn't a predicate; callers end up wrapping it in try/catch and the type confusion spreads. The && chain's short-circuiting is what makes the ordering enforceable in one expression.

Scope note: the prompt says letter, this checks ASCII. "é" and "ñ" return false. If Unicode letters were required, /^\p{L}$/u is the modern answer — naming that boundary is better than silently picking one.

Red flag: an unanchored regex as the only check — isLetter("ab") returns true and the validator becomes a rubber stamp. Anchor it or check the length; do one of them consciously.

Say it: "Guard chain: type, then length, then character class — because an unanchored regex test only asks 'contains', and the typeof guard makes the predicate total instead of throwable."