2878

How can I determine whether a variable is a string or something else in JavaScript?

0

35 Answers 35

1
2
0

A code to have only string without any numbers

isNaN("A") = true;
parseInt("A") = NaN;
isNaN(NaN) = true;

Than we can use isNaN(parseInt()) to have only the string

let ignoreNumbers = "ad123a4m";

let ign = ignoreNumbers.split("").map((ele) => isNaN(parseInt(ele)) ? ele : "").join("");

console.log(ign);

Sign up to request clarification or add additional context in comments.

Comments

0

This function is a safe way to check for any type:

let isType = (value, type) => {
    if (type == null || value == null) return value === type;
    return Object.getPrototypeOf(value ?? {}).constructor === type;
}

// All the following work as expected:
isType('abc', String);
isType(123, Number);
isType(/abc/, RegExp);
isType(null, null);
isType(undefined, undefined);

From this we can derive:

let isString = value => isType(value, String);

// Test this approach:

let isType = (value, type) => {
    if (type == null || value == null) return value === type;
    return Object.getPrototypeOf(value ?? {}).constructor === type;
}
let isString = value => isType(value, String);

let falseCases = [
  [ 'null', null ],
  [ 'undefined', undefined ],
  [ 'object', { a: 1, b: 2 } ],
  [ 'array', [ 1, 2, 3 ] ],
  [ 'number', 123 ],
  [ 'zero', 0 ],
  [ 'RegExp', new RegExp('hello') ],
  [ 'number with valueOf returning string', Object.assign(10, { valueOf: () => 'abc' }) ],
  [ 'object pretending to be string', { constructor: String } ]
];
let trueCases = [
  [ 'empty literal string', '' ],
  [ 'unicode string literal', String.fromCharCode(10000) ],
  [ 'empty boxed string', new String('') ],
  [ 'unicode boxed string', new String(String.fromCharCode(10000)) ],
  [ 'string with overwritten "constructor"', Object.assign('hi', { constructor: Array }) ],
  [ 'string with overwritten "toString"', Object.assign('hi', { toString: 123 }) ],
  [ 'string with overwritten "valueOf"', Object.assign('hi', { valueOf: 123 }) ],
  [ 'string with overwritten "constructor"', Object.assign('hi', { constructor: RegExp }) ],
  [ 'proxied string', new Proxy(new String('hello'), {}) ],
];

console.log('NEGATIVE TESTS:');
for (let [ name, val ] of falseCases) {
  console.log(`Test ${name}:\n  Expect: false\n  Got:    ${isString(val)}`); 
}

console.log('\nPOSITIVE TESTS:');
for (let [ name, val ] of trueCases) {
  console.log(`Test ${name}:\n  Expect: true\n  Got:    ${isString(val)}`); 
}

Comments

0

If you need to be 100% certain that a value or object is a string, this is the only answer that won't result in false positives or negatives in edge cases.

The following works because String.prototype.toString() only works on strings (both primitives and objects) and throws on all other values.

Finally, the strict equality check confirms that it can be cast as a string primitive without throwing.

function isString(value) {
    try {
        return "".toString.call(value)===String(value)
    }
    catch(e) {// not a string
        return false
    }
}

Be advised that try/catch is somewhat slow and that string objects that pass this test might have overwritten methods that prevent normal usage.

Consider using typeof to test only for string primitives or simply cast your value to a string.

Edit: This method uses the faster Object.prototype.toString() method when Symbol.toStringTag isn't in value. That prevents false positives when object looks like {[Symbol.toStringTag]:"String"} without the performance hit of try/catch:

function isString(value) {
    var toStringTag = typeof Symbol=="function" && Symbol.toStringTag// falsy where no support
    ,   type = typeof value
    ,   success = type=='string'
    
    if (type=='object' && value) {// test for String wrapper object
        if (toStringTag && toStringTag in value) {
            success = !function(){// isolate try/catch for better performance
                try{
                    type.toString.call(value);
                }
                catch(e) {
                    return true
                }
            }();
        }
        else {
            success = {}.toString.call(value)=='[object String]';
        }
    }
    return success;
}

Comments

-2

Below are two simple functions that should be fairly fast and work correctly for all the different types of string instances/variables. One for a scalar value check and the other for a vector of values to check.

const isString = x => ![null, undefined].includes(x) && !!x.toUpperCase
['', 'a', new String, String('a'), String(1)].map(v => isString(v)) // [true, true, true, true, true]
[null, undefined, 0, 1, true, [], ['a'], {}, {a: 'a'}].map(v => isString(v)) // [false, false, false, false, false, false, false, false, false]
const isStrings = x => x.map(v => ![null, undefined].includes(v) && !!v.toUpperCase).reduce((a, b) => a && b, true)
isStrings([]) // true
isStrings(['', 'a', new String, String('a'), String(1)]) // true
isStrings(['', 'a', new String, String('a'), String(1), 1]) // false
isStrings([0, 1, true, [], ['a'], {}, {a: 'a'}]) // false

Comments

-3

I'm not sure if you mean knowing if it's a type string regardless of its contents, or whether it's contents is a number or string, regardless of its type.

So to know if its type is a string, that's already been answered.
But to know based on its contents if its a string or a number, I would use this:

function isNumber(item) {
    return (parseInt(item) + '') === item;
}

And for some examples:

isNumber(123);   //true
isNumber('123'); //true
isNumber('123a');//false
isNumber('');    //false

1 Comment

I think I was originally asking how to check the type, although I didn't know how to even form the question back then. (and I'd probably just do this with /^\d+$/.test('123') to avoid the intricacies of potential parsing issues)
1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.