以下のコードはTypeScriptで書いてますがJavaScriptでも結論は同じはずです。
結論
lodashをimportして_.isStringを使うのが一番心配が少ない。
結論に至るまでの経緯
最初にやったこと
文字列かどうかを判定しようとしてinstanceofを使ったらうまくいかなかった。
let x = "string" as any // TypeScriptに怒られないようにわざとas anyしてるだけ
console.log("x:", x instanceof String) // -> false
調べた公式情報
JavaScript では、プリミティブ値の文字列とString オブジェクトの文字列は区別されます。(中略)JavaScript では、必要に応じてプリミティブ値の文字列が自動的に String オブジェクトに変換されるので、プリミティブ値の文字列に対して String オブジェクトのメソッドを使用することができます。
↑を踏まえて実験
let x = "abc" as any
let y = new String("abc")
console.log("x:", x instanceof String, typeof(x) == "string") // -> false, true
console.log("y:", y instanceof String, typeof(y) == "string") // -> true, false
つまり文字列かどうかの判定はx instanceof String || typeof(x) == "string"
としないといけない気がする。
ライブラリあるよね
まさか都度上の判定を書いてるとは思えなかったので調べたらやっぱりlodashにあった
import _ from "lodash-es"
let x = "abc" as any
let y = new String("abc")
console.log("x:", _.isString(x)) // -> true
console.log("y:", _.isString(y)) // -> true