How can I determine whether a variable is a string or something else in JavaScript?
32 Answers
This is what works for me:
if (typeof myVar === 'string' || myVar instanceof String)
// it's a string
else
// it's something else
// Test this approach:
let isString = value => typeof value === 'string' || value instanceof 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)}`);
}

- 7,358
- 2
- 35
- 55

- 30,559
- 2
- 26
- 28
-
153Does "myVar instanceof String" do anything above and beyond "typeof myVar == 'string'" ? – svth Apr 25 '12 at 13:59
-
If I am not wrong, typeof returns name of type as string ("string", "integer" ...) while instanceof compares actual types. I can't remember right now, but I think that in some cases typeof can return something other than "string" and thats why is double checked. – DRAX Apr 26 '12 at 09:56
-
120@svth I remembered. In JavaScript you can have variable type of string or type of object which is class of String (same thing - both are strings - but defined differently) thats why is double checked. – DRAX Apr 26 '12 at 10:04
-
54var somevar = new String('somestring') console.log(typeof somevar) // object – Danubian Sailor Jul 09 '13 at 08:52
-
4Just tested this: alert(new String() instanceof String); returns true in FireFox (while for example alert(new Object() instanceof String); returns false). – DRAX Dec 05 '13 at 18:29
-
147-1 because the `instanceof` check here is pointless noise unless you're following some *very unusual* coding practices, and this answer does nothing to explain what it does or why you might use it. The only reason you'd ever need it is if you use object-wrapped strings, but object-wrapped strings are a worthless feature that nobody uses and Google and Crockford both condemn as bad practice (https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Wrapper_objects_for_primitive_types#Wrapper_objects_for_primitive_types, http://www.crockford.com/javascript/recommend.html). – Mark Amery Aug 16 '15 at 17:34
-
8Also, if you're for some crazy reason using object-wrapped strings in your code, it's worth noting that the function here won't work with cross-frame code; it won't recognise object-wrapped strings that have been `postMessage`d from another frame because their constructor will be the `String` global from the *other* frame. This is an improbable hypothetical situation, but since you're already adding complexity to your solution to handle the improbable hypothetical situation of people using object-wrapped strings *at all*, I feel justified in pointing it out. – Mark Amery Aug 16 '15 at 17:38
-
1Indeed for general usage, it should be used primitive `string`. However there are some cases where using instances of `String` is more useful. For example, performance critical code could actually execute faster using `String` than primitive. http://pastebin.com/KAwht0ep – DRAX Sep 03 '15 at 07:25
-
3To sum up, I wouldn't call primitive wrappers "worthless feature", and code provided is not unusual at all. They have their use cases. – DRAX Sep 03 '15 at 07:31
-
206I strenuously disagree that writing solid code which correctly handles unlikely cases is something to be avoided. Checking both `typeof` and `instanceof` feels like good advice if your code may be called by others'. @MarkAmery's `postmessage` edge case matters if you're asking "what was I just `postmessage`d?" - but you'd expect that to be handled at the interface and not allowed to propagate. Elsewhere, it seems correct to handle non-deprecated coding methods even if some JS aesthetes disapprove of them. NEVER comment your code as accepting String, unless it truly does! – Dewi Morgan Sep 04 '15 at 04:11
-
That said, I may like @Ling's answer even more, as it handles MarkAmery's issue, too... – Dewi Morgan Sep 04 '15 at 04:15
-
1Perhaps Ling's answer is neater, but there are 2 things that you need to keep in mind: 1. Someone could modify `Object.prototype.toString` method and break code (which is highly unlikely to happen, but still...) 2. It is much slower to execute. – DRAX Sep 04 '15 at 07:14
-
2I think you can replace that condition by ```myVar.constructor === String```, it works for both cases: ```myVar = "Foobar"``` or ```myVar = new String("Foobar")``` – jbatista Sep 23 '15 at 14:55
-
That is interesting trick, but it will break if someone create `String` instance and change constructor and vice-versa (create instance of anything but `String` and then sets constructor to `String`). Both cases are unlikely to happen, but I prefer to create robust code. Also you will need to check if `myVar` is null as well. – DRAX Sep 24 '15 at 09:31
-
@MichaelTheriot the question here isn't just whether there are imaginable use-cases where the `instanceof` check could be useful (surely there are, if you're sufficiently creative, and also ones where it's harmful), it's whether it's more or less correct to use it than to omit it. The question asks how to check if a variable is a string. Is an object-wrapped String a string? Fuck if I know. It's unclear what, semantically, such a construct should be considered to represent, which is why they shouldn't be in the language in the first place and the style guides advise never to use them. – Mark Amery Jun 23 '16 at 16:56
-
1@MarkAmery Have you thought about editing this answer to include the information from your comment? Essentially it could say to just use typeof...unless you want to guard against those particularly bad coding practices, which almost nobody uses and nobody should, in which case you could include the instanceof check? Maybe either you or the OP could consider adding this information? – Panzercrisis Jun 23 '16 at 17:01
-
@MarkAmery There are several unconventional benefits of using string objects. If you are not performing strict equality / dropping them into a switch statement (property lookup is faster) I can't see a reason to exclude them. – Michael Theriot Jul 03 '16 at 04:10
-
2I could agree that this is checking for "noise", but this is the correct answer. What gets me is that SO doesn't move this to the top as it clearly has more upvotes. – Spets Oct 08 '16 at 18:04
-
1Is var obj = new String("some value") really a string? console.log(obj) shows more like a char array. Strings are instantiated with String("some value") (without new keyword) and typeof String(something) evaluates to "string". – Tires Nov 25 '16 at 14:55
-
1@Tires They are not instantiated without `new` keyword. Using `String(someValue)` is used for converting value (eg. number) to string, not for creating. – DRAX Nov 30 '16 at 18:33
-
@DanubianSailor thats a great example, its missing a semicolon. Interesting if the new keyword is omitted you get a 'string' : var Str = String(''); console.log(typeof Str, Str instanceof String); // string false – ekerner Apr 24 '17 at 08:10
-
`if(str.trim) {}` is a very simple hack that works in all scenarios. checking for the existance of `trim`, a method only part of the string prototype – bryc Dec 11 '17 at 14:39
-
1`let a:any = 'some string'; console.log(a instanceof String)` results in `false` on my machine. – Automatico Jan 17 '18 at 10:29
-
2Google. Crockford. Ok, well, whatever. This answer uses basic syntax and operators of the JavaScript language. It shows true understanding of the fundamental situation at hand. Winner. – Anthony Rutledge May 12 '18 at 21:49
-
...also if `!!('some string', String)` which return `true`. – darcher Oct 07 '18 at 18:38
-
@darcher: Unless I'm missing something, `('some string', String)` will always return `String`, which will always be truthy regardless of the type of the first argument. – Matthew Oct 24 '18 at 22:55
-
1@Matthew you're very right, was probably tipsy when I posted this and later found the error in my ways. – darcher Oct 25 '18 at 08:14
-
@bryc This doesn't work in all scenarios. It's perfectly valid for a non-`string` to have a method or property called `trim`. – Matthew Oct 25 '18 at 22:21
-
@Matthew Maybe it is not futureproof; if Array ever got a `trim` method, it would no longer work when comparing array to string. But it is still the shortest way to get a truthy value for checking for a string. – bryc Oct 26 '18 at 16:18
-
1@bryc I think you're only considering built-in types. Any [proto]type defined by you or a library could have a `trim` method or property, as well as any arbitrary object. – Matthew Oct 26 '18 at 20:48
-
1@DRAX: Is that the benchmark code you used to come to that conclusion? Because it sorts `arrPrim` twice instead of `arrPrim` then `arrObj`, uses `getMilliseconds` instead of `getTime`, and only runs once. After correcting these, primitives are consistently faster, as expected. Primitive wrappers are indeed worthless. – Ry- Nov 06 '19 at 05:15
-
@Ry- I can't remember, it was long time ago. But you are right that there is error in that code (arrPrim being sorted twice) and performance is slower when corrected. Thank you for correcting me. But I wouldn't say that wrappers are worthless. Here is one case that makes it perform better: https://jsbench.me/a4k2n4yynx Basically JS engines don't have shortcuts for custom methods, and they need to do wrapping of primitive to String object. – DRAX Nov 06 '19 at 10:39
-
2@DRAX: Side effect of missing strict mode and extending native prototypes. If you either use a regular function or add `'use strict'` inside the function, the primitive version will be faster (300x). – Ry- Nov 06 '19 at 10:47
-
@Ry- You are correct. Here is updated code: https://jsbench.me/tuk2n5xsuz – DRAX Nov 06 '19 at 10:54
-
1`"somestring" instanceof String` resolves to `false` – SmileyJames Apr 30 '20 at 16:13
-
2@SmileyJames that is correct, and `new String("somestring") instanceof String` resolves to `true` – DRAX May 18 '20 at 11:33
-
@SmileyJames - correct, which is why Drax has two different tests. The first one is for primitive strings `typeof `"somestring" === string`, the second test is for String objects ``new String("somestring" instanceof String`. – ToolmakerSteve Jul 10 '21 at 21:48
-
@ruffin the prose was pretty confusing and some of the claims made strike me as just plain wrong. I can see arguing that `"foo"` and `new String("foo")` are both strings (though it's not obvious to me as a point of terminology whether `String` objects wrapping strings *should* count as "strings" are not), but they're definitely not "the same" as the edit states - they have important behavioural differences (e.g. https://stackoverflow.com/a/24320766/1709587), and `new String("foo")` is an *instance* of `String`, not *"a class of String"*. – Mark Amery Aug 10 '21 at 08:48
-
1@ruffin I don't object at all to some explanation being added, but such an edit should explain 1. that `new String("foo")` and `"foo"` evaluate to values with different types with differences in how they behave (which go beyond how they show up to `typeof` and `instanceof` checks), 2. that the `typeof` check lets you detect the non-object-wrapped strings while the `instanceof` check lets you detect the object-wrapped ones. IMO the edit I reverted wasn't clear about the second point and seemed to actively contradict the first one, so I think it did more harm than good. – Mark Amery Aug 10 '21 at 08:53
-
1@MarkAmery Thanks for the clarification; makes perfect sense. (I'd asked why [he'd reverted an edit](https://stackoverflow.com/revisions/9436948/5) where someone (awkwardly) [tried to add the content from his comments here to the answer](https://stackoverflow.com/revisions/9436948/4)). – ruffin Aug 10 '21 at 16:45
-
For whatever reason I had to declare a variable like this. var mytype = typeof myobj; if (mytype == "string") ..... – Rob Aug 29 '22 at 21:01
-
This is superficial at the best, and fundamentally complicated. An instance of Object is not a data type. It may be obvious, may be "Nah! JS auto-boxes it and you can work with both interchangeably in real-world", but that fact brings some fundamental points. It works for me, it works for you, it works for 95% of the cases, until it doesn't and we have a hard bug to debug. For example: `a` is `String`, `b` is `string`. Unexpected outputs can occur, having `typeof a == 'object', a instanceof Object` (`true, true`) and this solution, especially if it's buried in a deeply nested node_modules lib. – Andre Figueiredo Sep 01 '23 at 15:37
You can use typeof
operator:
var booleanValue = true;
var numericalValue = 354;
var stringValue = "This is a String";
var stringObject = new String("This is a String Object");
console.log(typeof booleanValue) // displays "boolean"
console.log(typeof numericalValue) // displays "number"
console.log(typeof stringValue) // displays "string"
console.log(typeof stringObject) // displays "object"
Example from this webpage. (Example was slightly modified though).
This won't work as expected in the case of strings created with new String()
, but this is seldom used and recommended against[1][2]. See the other answers for how to handle these, if you so desire.
// Test this approach:
let isString = value => typeof 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)}`);
}
- The Google JavaScript Style Guide says to never use primitive object wrappers.
- Douglas Crockford recommended that primitive object wrappers be deprecated.

- 7,358
- 2
- 35
- 55

- 176,835
- 32
- 241
- 292
-
52@Wolfy87 Please be advised that there are some cases that typeof stringValue might return "object" instead of "string". See comments on my answer. – DRAX Apr 26 '12 at 10:07
-
219My preferred answer. The argument against it is that it 'fails' for object-wrapped strings like `new String('foo')`, but that doesn't matter because object-wrapped strings are a worthless feature that you shouldn't be using. The Google style guide [forbids them](https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Wrapper_objects_for_primitive_types#Wrapper_objects_for_primitive_types), Douglas Crockford [wants them deprecated](http://www.crockford.com/javascript/recommend.html), and no libraries use them. Pretend they don't exist, and use `typeof` without fear. – Mark Amery Jun 06 '14 at 21:13
-
8Didn't [Douglas Crockford recommend that `typeof` be deprecated](http://www.crockford.com/javascript/recommend.html) as well? – Daniel Le Oct 02 '17 at 09:11
-
12@DanielLe, because he proposed a replacement that fixes some issues, not because he's against it in principle. – Vsevolod Golovanov Dec 06 '17 at 17:30
-
1@VsevolodGolovanov How do you know that he's not against it in principle? All I know is those issues are precisely why he recommended that the current implementation of `typeof` be deprecated. – Daniel Le Dec 07 '17 at 09:39
-
1
-
@MarkAmery what's the use case for declaring a `string` that way? Seems like bad practice. – Thomas May 12 '18 at 15:02
-
5@MarekMarczak Not sure I understand: NaN is a special IEEE floating point value, and should absolutely be considered a number in every programming language that uses IEEE floats, with a _value_ that indicates it will yield undefined behaviour if you plug it into further maths statements. Just like Infinity. – Mike 'Pomax' Kamermans Oct 02 '18 at 18:29
-
@Mike'Pomax'Kamermans maybe NaN type could be useful in scientific calculations and represents infinity but in everyday programming it causes a headache. – Marek Marczak Oct 03 '18 at 12:26
-
6If it causes you headaches, 99.99% of the time that's because you did not structure your code correctly. That's not NaN's fault for existing and doing what it does, that's something you should take note of, learn from, and bear in mind the next time you work with code that might yield it. – Mike 'Pomax' Kamermans Oct 03 '18 at 15:44
-
1If you, guys, look in the `'path'` module code of NodeJS you will see there just `if (typeof path !== 'string')`[[1](https://github.com/nodejs/node/blob/master/lib/path.js#L611)][[2](https://github.com/nodejs/node/blob/master/lib/internal/validators.js#L124)]. Just imagine what a huge number of users of this module is and no one complains about the problem with the object wrappers! – Serg Jan 26 '19 at 14:39
-
This is a tricky question that has been already answered here: https://stackoverflow.com/questions/50082312/difference-between-string-and-new-string-in-javascript/64308392#64308392 – twboc Mar 09 '21 at 19:25
function isString(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
Or, inline (I have an UltiSnip setup for this):
Object.prototype.toString.call(myVar) === "[object String]"
FYI, Pablo Santa Cruz's answer is wrong, because typeof new String("string")
is object
DRAX's answer is accurate and functional and should be the correct answer (since Pablo Santa Cruz is most definitely incorrect, and I won't argue against the popular vote.)
However, this answer is also definitely correct, and actually the best answer (except, perhaps, for the suggestion of using lodash/underscore). disclaimer: I contributed to the lodash 4 codebase.
My original answer (which obviously flew right over a lot of heads) follows:
I transcoded this from underscore.js:
['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'].forEach(
function(name) {
window['is' + name] = function(obj) {
return toString.call(obj) == '[object ' + name + ']';
};
});
That will define isString, isNumber, etc.
In Node.js, this can be implemented as a module:
module.exports = [
'Arguments',
'Function',
'String',
'Number',
'Date',
'RegExp'
].reduce( (obj, name) => {
obj[ 'is' + name ] = x => toString.call(x) == '[object ' + name + ']';
return obj;
}, {});
[edit]: Object.prototype.toString.call(x)
works to delineate between functions and async functions as well:
const fn1 = () => new Promise((resolve, reject) => setTimeout(() => resolve({}), 1000))
const fn2 = async () => ({})
console.log('fn1', Object.prototype.toString.call(fn1))
console.log('fn2', Object.prototype.toString.call(fn2))
// Test this approach:
function isString(x) {
return Object.prototype.toString.call(x) === "[object 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)}`);
}

- 101
- 3
- 12

- 13,235
- 3
- 69
- 45
-
21You recommend underscore.js (for what odd reason?) but you don't use it here. Moreover you pollute the global namespace with functions. In node.js you'd create a module that'd have all these functions (you _can_ use `global || window` instead of `window` but that would be a bad approach to solve a problem you shouldn't have in the first place). – Benjamin Gruenbaum Jul 21 '13 at 12:13
-
24@BenjaminGruenbaum I came looking for the answer to the OP's question, and didn't like any of the answers. So I checked what underscore did, and thought it was nifty enough to extract and modify a little (to avoid having to have the underscore library loaded). I'll clarify my post. – Orwellophile Aug 03 '13 at 00:06
-
4@Orwellophile Cool, I get it now, your original answer was phrased like you're suggesting underscore itself. Personally I'd just check `myObject+"" === myObject` to check if an object is a string (or even better, I wouldn't type check in a behavior driven type system in the first place). – Benjamin Gruenbaum Aug 03 '13 at 00:13
-
1@BenjaminGruenbaum well, I guess I am suggesting underscore :) I find that when I use my own methods (like that one you just posted), I tend to use different checks in different pieces of code. Eventually I grow paranoid that a particular variant may be incorrect, and I end up double checking, rewriting, etc. So for me, a definitive isWhatever() means that I can be consistent, and if it turns out to ever be wrong, I can change it one place only. Also, I can create matching functions in other languages (I'm doing BASH now) and have a consistent naming convention. – Orwellophile Aug 09 '13 at 04:31
-
3@BenjaminGruenbaum `myObject+"" === myObject` won't work in the case `myObject = new String("string")`. you have to use `myObject instanceof String`. See DRAX's answer – Utopik Oct 11 '13 at 14:43
-
3@Utopik in that case it's not the same, a primitive and a wrapped value are not the same. A `String` object has a completely different behavior from a string primitive value type (try adding a propert for example). DRAX's answer is wrong in that regard imo. – Benjamin Gruenbaum Oct 11 '13 at 14:45
-
1DRAX's answer may be wrong only in prototypal inheritance context, depending on what you're trying to achieve. In others cases, it is correct – Utopik Oct 11 '13 at 15:13
-
2
-
2FYI. Wrong for `NaN`. Check. `toString.call(1-"a") => "[object Number]"`. But actually `1-"a" ==> NaN` – Green Oct 19 '16 at 10:34
-
2@Green `NaN` is still an instance of `Number`, specifically `Number.NaN`. `typeof NaN` also returns "number", in case anybody else is wondering. *Either way, it's not a String, which is what this question is about.* – Orwellophile Oct 19 '16 at 13:18
-
2Interestingly, Array.isArray is becoming a standard function with a recommended shim implementation identical to `Object.prototype.toString.call(arg) == '[object Array]'`. I don't see any reason why an identical method shouldn't exist as `String.isString = function(arg){return Object.prototype.toString.call(arg) == '[object String]';}` It just works. I love the iteration to define these for other classes like Function, Number, etc.... but why pollute the global namespace? Why not follow the lead of Array.isArray add them as 'static' methods on their corresponding types? – Triynko Nov 04 '16 at 18:41
-
1Indeed, that's just what appealed to me. I have an editor (VIM) macro that expands `isAnything` to `Object.prototype.toString.call(arg) == '[object ${Anything}]` so I am always covered, even if I need something rare like `isArguments` – Orwellophile Nov 05 '16 at 15:59
-
35
-
1Is the rendering of `toString` for objects standardised? Or could a future standards-compliant browser implement Object.toString as rendering `"[Dude its an Object!]"`? – dualed Feb 17 '18 at 17:00
-
1@dualed [Yes](https://www.ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring). Note also that because we use `toString.call()`, this cannot be exploited with something like `x = { toString: () => '[object Number]' }`. – Jonathan H May 07 '18 at 17:54
-
7JS supports monkey patching, so it's possible to re-define the `toString` in the `Object.prototype`. So, I'd argue that relying on `toString` to check an object's type is, at best, a bad practice. – Andre Rodrigues Jul 26 '18 at 01:44
-
1This answer looks complete, but I am curious about performance of this versus `typeof`. – HoldOffHunger Aug 02 '18 at 19:27
-
10i support having "wrong answer" and "shotgun-style answer" refer to post more specifically since the numbers of replies have aged, and then also explain why those answers are inferior as you present superior answer. my two-cents. – SmokeRaven Nov 26 '19 at 22:13
-
3It’s not a popularity contest. People will use which ever answer suits them best. I liked my answer because it shows by example that the method used for checking type is applicable to many object types. I like methods that are consistent, and I like the DRY principle. I also like that the answer is from one of the most popular JS libraries, and has been tested on every conceivable platform and on thousands of really big sites. **Adding extra functions to Objects is just bad form**. I’m not forcing anyone to define global functions either, just presenting a simpler version of lodash code. – Orwellophile Mar 03 '20 at 07:15
-
4-1 because this doesn't really add anything compared to [DRAX's answer](https://stackoverflow.com/a/9436948/1709587), and because it characterises [Pablo's answer](https://stackoverflow.com/a/4059166/1709587) as wrong for not treating `new String("string")` as a string without providing any argument for why it _should_ be treated as a string. (IMO, it shouldn't be. Object-wrapped strings are not the same thing as strings and behave differently. TypeScript agrees with me, for what it's worth; `const foo: string = new String("string")` is a compilation error.) – Mark Amery Nov 26 '21 at 10:47
-
1thank you @Orwellophile for giving an answer that not only laconically answers the narrow question, but also enriches the readers' knowledge and preparedness for similar problems. – alex Apr 14 '22 at 07:11
-
1@MarkAmery I didn't make the rules Mark, if `toString.call(new String("string")) == '[object String]'` then I'm afraid it's a string. Also, `(new String('test')).toString() === 'test'`. It's your right to disagree. – Orwellophile Apr 20 '22 at 07:51
-
1This is the best answer and regret to say some of the commentators seem to not read English too well. @Orwellophile did *NOT* _recommend_ underscore, but rather he _referred_ to it as his source of wisdom. Also, arguments like "you can redefine toString" (@Andre Rodrigues) deserve replies like "Get your **** together." Your code, you should know what is being redefined, and calling bad practice on the same breath as suggesting redefining standard methods is precious. As for future possible incompatibilities, welcome to the World. – Ricardo Jun 02 '23 at 16:16
-
@Ricardo Looks like you misunderstood me, which is kind of ironic.I didn’t recommend redefining the toString method, I said it’s a possibility. So if that happens (and it can happen outside your code base), then this solution might break. It’s a long shot, I’ll give you that, but just throwing it ou there. – Andre Rodrigues Jun 04 '23 at 00:22
I recommend using the built-in functions from jQuery or lodash/Underscore. They're simpler to use and easier to read.
Either function will handle the case DRAX mentioned... that is, they both check if (A) the variable is a string literal or (B) it's an instance of the String object. In either case, these functions correctly identify the value as being a string.
lodash / Underscore.js
if(_.isString(myVar))
//it's a string
else
//it's something else
jQuery
if($.type(myVar) === "string")
//it's a string
else
//it's something else
See lodash Documentation for _.isString() for more details.
See jQuery Documentation for $.type() for more details.

- 4,960
- 4
- 41
- 52
-
157This is the essential of what is wrong with JS community - checking against primitive type is a one-liner and involves just language construction (one of the basic), but you recommend using external library. If someone already uses one of these libraries it might be a good idea, but downloading them just for that instead of simply checking the type is an overkill. – Rafał Wrzeszcz Oct 25 '16 at 10:32
-
6I'm going to agree with Rafal. I'm seeing everywhere that it improves "readability" to use one of these external libraries. If you know JavaScript, then that is easier to read than some external library you haven't used. `_.every()` is a little confusing to use at first, and something as simple as `_.isBoolean()` has confused devs at my company. A dev mistakenly thought it would be false if the value was a boolean and was false. English is easier to read than German for me, because I don't know German. Learn JavaScript and it will all make sense. – John Harding Apr 06 '17 at 16:33
-
22@RafałWrzeszcz These libraries are fairly widely used and provide much useful (and tested) functionality. Especially lodash. I wouldn't recommend someone download the library only to use for this one solution.... but I would recommend every javascript developer download this library and see what they are missing out on. ;) – Jason Parker May 24 '17 at 10:27
-
2In production, you'd want things to work as fast as possible and while a library significantly cuts down development time, it could increase application complexity by adding a layer of abstraction. Every developer has to study the library to use it instead of a "simple" language construct. The takeaway is this: If you're going to use a library for your application, only add it if you know you'll be doing more than two or three one-liners or "checks" of this sort :) – SidOfc Aug 23 '17 at 10:11
-
1
-
23All y'all are missing the point of a library like Lodash: not speed. Not "ease of development". **The reason** to use a library like Lodash provides "defensiveness" against issues that will blow up your js app. Fatal errors happen when you attempt to do string operations on an object (or vice versa), and Lodash provides tremendous value around preventing those errors. – random_user_name Oct 17 '17 at 21:15
-
1Bear in mind that many people will be doing this in a Node or Node-like environment, and very few people will be using jQuery there. – Matt Fletcher Jan 22 '18 at 09:51
-
For client side Apps, the size issue can be mitigated through proper bundling / tree shaking which you should have in place anyway. Also, I haven't seen any normal sized project without lodash or a similar lib. See my answer below. – Erez Cohen Jul 22 '19 at 20:52
-
10All of these comments are valid but, man...only with JS would the suggestion of using a third-party library to _check a type_ not get you laughed out of the dev room. – MickMalone1983 Dec 09 '20 at 14:50
-
If I am already using lodash (or equivalent) I would not mind using library capabilities to get my work done. I would however not prefer to use it solely for one operation – Ashwin May 26 '21 at 03:24
Edit: The current way to do it is typeof value === 'string'
. For example:
const str = 'hello';
if (typeof str === 'string') { ... }
Below has been deprecated since node v4.
If you work on the node.js environment, you can simply use the built-in function isString in utils.
const util = require('util');
if (util.isString(myVar)) {}

- 2,528
- 1
- 23
- 29
-
-
4
-
2`x = new String('x'); x.isString(x);` returns *false*. There is `util.types.isStringObject()` but that returns false for `x = 'x'` type string. Two utility functions that provide absolutely no utility... – spinkus Apr 17 '20 at 07:29
function isString (obj) {
return (Object.prototype.toString.call(obj) === '[object String]');
}
I saw that here:
http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
-
4I think this solution is the most robust since it handles cross-frame/cross-window reference scenarios as mentioned in the URL provided in the answer. – ewh May 28 '15 at 06:53
-
1
-
2@ling Just curious, why do you put parenthesis around `Object.prototype.toString.call(obj) === '[object String]'`? – StubbornShowaGuy Dec 06 '16 at 05:37
-
@Earlee You mean `(x === y)` has better readability than `x === y`? – StubbornShowaGuy Oct 10 '17 at 06:15
-
@StubbornShowaGuy In my opinion, yes. It's also about consistency. I personally always use parentheses when returning a value. – Aquarelle Jan 24 '18 at 04:10
-
2
-
1@JonathanH - if you look at the edit history of Orwellophile's answer, at the time *this* answer was written, Orwellophile said something quite complex. It was only in 2016 that that answer was edited to include this. So ling should get the credit! – ToolmakerSteve Jul 10 '21 at 21:57
Best way:
var s = 'String';
var a = [1,2,3];
var o = {key: 'val'};
(s.constructor === String) && console.log('its a string');
(a.constructor === Array) && console.log('its an array');
(o.constructor === Object) && console.log('its an object');
(o.constructor === Number || s.constructor === Boolean) && console.log('this won\'t run');
Each of these has been constructed by its appropriate class function, like "new Object()" etc.
Also, Duck-Typing: "If it looks like a duck, walks like a duck, and smells like a duck - it must be an Array" Meaning, check its properties.
Hope this helps.
Edit; 12/05/2016
Remember, you can always use combinations of approaches too. Here's an example of using an inline map of actions with typeof:
var type = { 'number': Math.sqrt.bind(Math), ... }[ typeof datum ];
Here's a more 'real world' example of using inline-maps:
function is(datum) {
var isnt = !{ null: true, undefined: true, '': true, false: false, 0: false }[ datum ];
return !isnt;
}
console.log( is(0), is(false), is(undefined), ... ); // >> true true false
This function would use [ custom ] "type-casting" -- rather, "type-/-value-mapping" -- to figure out if a variable actually "exists". Now you can split that nasty hair between null
& 0
!
Many times you don't even care about its type. Another way to circumvent typing is combining Duck-Type sets:
this.id = "998"; // use a number or a string-equivalent
function get(id) {
if (!id || !id.toString) return;
if (id.toString() === this.id.toString()) http( id || +this.id );
// if (+id === +this.id) ...;
}
Both Number.prototype
and String.prototype
have a .toString() method
. You just made sure that the string-equivalent of the number was the same, and then you made sure that you passed it into the http
function as a Number
. In other words, we didn't even care what its type was.
Hope that gives you more to work with :)
-
1You would need some other check for plain old numbers, since trying to take their constructor property will fail: – Jun 17 '13 at 05:18
-
@torazaburo Worked fine for me just now in the Chrome console. What makes you think it won't work? – Mark Amery Jun 06 '14 at 21:04
-
2@torazaburo You may want to play with the assertions ( `(o.constructor === Number || s.constructor === Boolean)` ). Anecdotally, `parseInt` and `NaN` are fragile but powerful tools. Just remember, Not-a-Number is NOT Not-a-Number, and undefined can be defined. – Cody Jun 11 '14 at 23:18
-
1a.constructor === Array is wrong and can fail sometimes, use Array.isArray see http://web.mit.edu/jwalden/www/isArray.html – axkibe Sep 17 '14 at 11:06
-
1Agreed, this isn't fail-safe. A better way is to use property checks -- THAT'S the only truly fail-safe way at the moment. Example: `if(thing.call) { 'its a function'; }` or `if(thing.defineProperties) { 'its an object'; }`. Thanks for the input, axkibe! – Cody Sep 29 '14 at 19:31
I can't honestly see why one would not simply use typeof
in this case:
if (typeof str === 'string') {
return 42;
}
Yes it will fail against object-wrapped strings (e.g. new String('foo')
) but these are widely regarded as a bad practice and most modern development tools are likely to discourage their use. (If you see one, just fix it!)
The Object.prototype.toString
trick is something that all front-end developers have been found guilty of doing one day in their careers but don't let it fool you by its polish of clever: it will break as soon as something monkey-patch the Object prototype:
const isString = thing => Object.prototype.toString.call(thing) === '[object String]';
console.log(isString('foo'));
Object.prototype.toString = () => 42;
console.log(isString('foo'));

- 17,580
- 5
- 58
- 84
-
4FWIW; Arguing against a solution because it could be broken by monkey-patching the Object prototype is a weak argument. In a dynamic language, almost anything can be broken by doing stuff you shouldn't do! – ToolmakerSteve Jul 10 '21 at 22:09
-
3@ToolmakerSteve Fair. You are right of course. Someone could easily alter all native prototypes and nothing would work anymore. I guess the point I was trying to make is that in a (JS) world where monkey patching is still common practice, relying on such technique is fraught with danger and one shouldn't expose themselves to it when the (simpler) alternative is guaranteed to always work (AFAIK you cannot monkey patch `typeof`). Point taken nonetheless. Thank you. – customcommander Jul 10 '21 at 22:33
-
1Its a trade-off:, given that the two approaches don't always return the same answer. So it depends on your "spec" - what you mean by a string. *"fraught with danger"* seems a bit strong in this case. If someone modifies `Object.prototype.toString` such that it returns a different result... frankly that's their problem! IMHO the possibility shouldn't be a factor in deciding what approach to use. (I personally don't bother; I go with the simple approach you show - but then I'm not writing library code.) – ToolmakerSteve Jul 12 '21 at 16:03
Performance
Today 2020.09.17 I perform tests on MacOs HighSierra 10.13.6 on Chrome v85, Safari v13.1.2 and Firefox v80 for chosen solutions.
Results
For all browsers (and both test cases)
- solutions
typeof||instanceof
(A, I) andx===x+''
(H) are fast/fastest - solution
_.isString
(lodash lib) is medium/fast - solutions B and K are slowest
Update: 2020.11.28 I update results for x=123 Chrome
column - for solution I
there was probably an error value before (=69M too low) - I use Chrome 86.0 to repeat tests.
Details
I perform 2 tests cases for solutions A B C D E F G H I J K L
Below snippet presents differences between solutions
// https://stackoverflow.com/a/9436948/860099
function A(x) {
return (typeof x == 'string') || (x instanceof String)
}
// https://stackoverflow.com/a/17772086/860099
function B(x) {
return Object.prototype.toString.call(x) === "[object String]"
}
// https://stackoverflow.com/a/20958909/860099
function C(x) {
return _.isString(x);
}
// https://stackoverflow.com/a/20958909/860099
function D(x) {
return $.type(x) === "string";
}
// https://stackoverflow.com/a/16215800/860099
function E(x) {
return x?.constructor === String;
}
// https://stackoverflow.com/a/42493631/860099
function F(x){
return x?.charAt != null
}
// https://stackoverflow.com/a/57443488/860099
function G(x){
return String(x) === x
}
// https://stackoverflow.com/a/19057360/860099
function H(x){
return x === x + ''
}
// https://stackoverflow.com/a/4059166/860099
function I(x) {
return typeof x == 'string'
}
// https://stackoverflow.com/a/28722301/860099
function J(x){
return x === x?.toString()
}
// https://stackoverflow.com/a/58892465/860099
function K(x){
return x && typeof x.valueOf() === "string"
}
// https://stackoverflow.com/a/9436948/860099
function L(x) {
return x instanceof String
}
// ------------------
// PRESENTATION
// ------------------
console.log('Solutions results for different inputs \n\n');
console.log("'abc' Str '' ' ' '1' '0' 1 0 {} [] true false null undef");
let tests = [ 'abc', new String("abc"),'',' ','1','0',1,0,{},[],true,false,null,undefined];
[A,B,C,D,E,F,G,H,I,J,K,L].map(f=> {
console.log(
`${f.name} ` + tests.map(v=> (1*!!f(v)) ).join` `
)})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>
This shippet only presents functions used in performance tests - it not perform tests itself!
And here are example results for chrome

- 85,173
- 29
- 368
- 345
-
Have you tried running your tests multiple times? I have strong doubt about strategy "i", running on Chrome with x = 123. You get 69M, though you get 671M for case A (which is essentially the same code, with an extra test). Here, that strategy wins in Chrome for x = 123. Not that important, honestly, but just a reminder that performance micro benchmarks are very difficult to get right. – James Nov 16 '20 at 16:15
-
yep - I run test multiple times in past - I also run It now - and you have right - now result for I is much better (I have 674M for "i") - I will update this (in free time) - thank you – Kamil Kiełczewski Nov 16 '20 at 16:28
-
@jwatkins - I update table with results - thanks for you comment :) – Kamil Kiełczewski Nov 28 '20 at 21:26
-
This is very, very useful - thanks! But some of the timed tests are arguably not correct - e.g. `x + '' === x` fails for strings created with `new String("string")`. Perhaps it should be limited to correct tests, or at least have added columns for the result of each test for a simple test suite of e.g. `null`, `undefined`, `123`, `new Object()` (should all give `false`) and `""`, `"abc"`, `new String("")`, `new String("abc")` (should all give `true`). – MikeBeaton Jul 11 '21 at 08:16
-
Test A seems to be getting a slight speedup (at least in Chrome on macOS) from using `==` instead of `===` - but not sure if this matters. – MikeBeaton Jul 11 '21 at 08:18
-
The `x.charAt` test is not reliable and could introduce security flaws. – Gershom Maes May 19 '23 at 13:25
-
this a moo point, Performance just matter after Feature, after standardizing test cases. it's not useful if you are comparing a code that output different results – Andre Figueiredo Sep 01 '23 at 14:00
This is a great example of why performance matters:
Doing something as simple as a test for a string can be expensive if not done correctly.
For example, if I wanted to write a function to test if something is a string, I could do it in one of two ways:
1) const isString = str => (Object.prototype.toString.call(str) === '[object String]');
2) const isString = str => ((typeof str === 'string') || (str instanceof String));
Both of these are pretty straight forward, so what could possibly impact performance? Generally speaking, function calls can be expensive, especially if you don't know what's happening inside. In the first example, there is a function call to Object's toString method. In the second example, there are no function calls, as typeof and instanceof are operators. Operators are significantly faster than function calls.
When the performance is tested, example 1 is 79% slower than example 2!
See the tests: https://jsperf.com/isstringtype

- 20,879
- 9
- 40
- 61

- 3,702
- 1
- 20
- 33
-
The test link is dead, but I believe you. This kind of information is super important. IMHO this should be, if not the most upvoted answer, at least the most upvoted comment on the current leading answer. – Coderer Jan 03 '19 at 17:00
-
`typeof str === 'string' || str instanceof String` (can drop the parenthesis which I prefer in `if (..)` cases); regardless, checking both the primitive and object types in #2 is clear and sufficient. These checks should be 'rare' anyway. – user2864740 Jan 22 '19 at 20:48
-
1[here](http://jsbench.github.io/#9ea2f56bba30fed35f1b5f2b22954d4e) is a benchmark, 30x faster on firefox, 2 nanoseconds vs 50 ns – milahu Oct 02 '20 at 19:37
-
1Yeah, @MilaNautikus the only issue with the `Boolean(str.charCodeAt)` solution is that it doesn't handle the case of undefined/null; otherwise I could have just said `const isString = str => str.charCodeAt !== undefined` for the same performance – Rob Brander Oct 05 '20 at 18:27
I like to use this simple solution:
var myString = "test";
if(myString.constructor === String)
{
//It's a string
}

- 3,204
- 3
- 32
- 42
-
4
-
4@Sheljohn Cody's answer is great. My answer (complete text) is shorter and straight to the point. You asked... :) – ScottyG May 08 '18 at 22:03
-
1As a function, this would need a way of dealing with `undefined` and `null`, and still getting the answer right for empty strings (both `''` and `new String('')`). – MikeBeaton Feb 24 '20 at 10:48
-
1@MikeBeaton No problem: `(mystring || false) && mystring.constructor === String`. I used false in case it's used in a function that must return a boolean. – alans Apr 24 '20 at 16:59
-
@MikeBeaton - do empty strings return a different answer for `.constructor`? That would be quite surprising. – ToolmakerSteve Jul 10 '21 at 22:12
-
No, just pointing out that `""` and `new String("")` have different boolean values, which complicates getting the code right. I think code someone else suggested in these comments doesn't quite work, for that very reason. – MikeBeaton Jul 11 '21 at 07:42
-
So we need something like `myString === '' || (!!myString && myString.constructor === String)` – MikeBeaton Jul 11 '21 at 07:48
-
@MikeBeaton or just `myString != null && myString.constructor === String`. But yeah, `null` and `undefined` are complications that this answer doesn't handle as written, so -1. – Mark Amery Nov 26 '21 at 19:17
I find this simple technique useful to type-check for String -
String(x) === x // true, if x is a string
// false in every other case
const test = x =>
console.assert
( String(x) === x
, `not a string: ${x}`
)
test("some string")
test(123) // assertion failed
test(0) // assertion failed
test(/some regex/) // assertion failed
test([ 5, 6 ]) // assertion failed
test({ a: 1 }) // assertion failed
test(x => x + 1) // assertion failed
The same technique works for Number too -
Number(x) === x // true, if x is a number
// false in every other case
const test = x =>
console.assert
( Number(x) === x
, `not a number: ${x}`
)
test("some string") // assertion failed
test(123)
test(0)
test(/some regex/) // assertion failed
test([ 5, 6 ]) // assertion failed
test({ a: 1 }) // assertion failed
test(x => x + 1) // assertion failed
And for RegExp -
RegExp(x) === x // true, if x is a regexp
// false in every other case
const test = x =>
console.assert
( RegExp(x) === x
, `not a regexp: ${x}`
)
test("some string") // assertion failed
test(123) // assertion failed
test(0) // assertion failed
test(/some regex/)
test([ 5, 6 ]) // assertion failed
test({ a: 1 }) // assertion failed
test(x => x + 1) // assertion failed
Same for Object -
Object(x) === x // true, if x is an object
// false in every other case
NB, regexps, arrays, and functions are considered objects too.
const test = x =>
console.assert
( Object(x) === x
, `not an object: ${x}`
)
test("some string") // assertion failed
test(123) // assertion failed
test(0) // assertion failed
test(/some regex/)
test([ 5, 6 ])
test({ a: 1 })
test(x => x + 1)
But, checking for Array is a bit different -
Array.isArray(x) === x // true, if x is an array
// false in every other case
const test = x =>
console.assert
( Array.isArray(x)
, `not an array: ${x}`
)
test("some string") // assertion failed
test(123) // assertion failed
test(0) // assertion failed
test(/some regex/) // assertion failed
test([ 5, 6 ])
test({ a: 1 }) // assertion failed
test(x => x + 1) // assertion failed
This technique does not work for Functions however -
Function(x) === x // always false
For @Faither -
const fmt = JSON.stringify
function test1() {
const a = "1"
const b = 1
console.log(`Number(${fmt(a)}) === ${fmt(b)}`, Number(a) === b) // true
}
function test2() {
const a = "1"
const b = 1
console.log(`Number.isInteger(${fmt(a)})`, Number.isInteger(a)) // false
console.log(`Number.isInteger(${fmt(b)})`, Number.isInteger(b)) // true
}
function test3() {
name = 1 // global name will always be a string
console.log(fmt(name)) // "1"
console.log(`String(${fmt(name)}) === ${fmt(name)}`, String(name) === name) // true
}
function test4() {
const name = 1 // local name
console.log(fmt(name)) // 1
console.log(`String(${fmt(name)}) === ${fmt(name)}`, String(name) === name) // false
}
test1(); test2(); test3(); test4()

- 129,518
- 31
- 228
- 259
-
`var x = new String(x); String(x)===x` returns false. however `({}).toString.call(x).search(/String/)>0` always returns for stringy things – unsynchronized Jan 03 '20 at 12:53
-
1`function isClass(x,re){return ({}).toString.call(x).search(re)>0;};` `isClass("hello",/String/)` or `isClass(3,/Number/)` or `isClass(null,/Null/)` – unsynchronized Jan 03 '20 at 13:12
-
This technique seems "non obvious" to me. Clever techniques that "work", but don't clearly express the intent, I find distasteful. – ToolmakerSteve Jul 10 '21 at 22:27
-
There is nothing clever about it. Constructors that receive an argument of the same type return the argument, unmodified. Maybe you’re simply unaware of this property? See also [idempotence](https://en.m.wikipedia.org/wiki/Idempotence) – Mulan Jul 11 '21 at 16:05
-
2@unsynchronized It's not obvious that `new String(x)` _should_ count as a string, though. It's a wrapper object, with different behaviour to a normal string. Unless you for some weird reason have specific requirements about how you want your check to handle string wrapper objects (which you probably don't, because there's no reason to ever use them in the first place), it's not really a strike against this answer. – Mark Amery Nov 26 '21 at 19:13
-
`Number('1') === 1` returns `true`, though. `Number.isInteger('1')` is `false`. – Artfaith Oct 12 '22 at 12:27
-
-
@Faither `Number("1")` equals `1`, `Number` converts the string `"1"` to `1`. And `Number.isInteger("1")` is false because `"1"` is a string, not an integer. And `name = 1; String(name) === name` is true because **global** `name` is a `window` property and will always be a string, `name = 1; typeof name` will show `string`. I updated my answer with test examples. – Mulan Oct 12 '22 at 13:57
if (s && typeof s.valueOf() === "string") {
// s is a string
}
Works for both string literals let s = 'blah'
and for Object Strings let s = new String('blah')

- 2,975
- 2
- 21
- 32
-
10Attention! This will fail on empty strings, since those are falsey. – Philipp Sumi Mar 07 '20 at 13:15
Taken from lodash:
function isString(val) {
return typeof val === 'string' || ((!!val && typeof val === 'object') && Object.prototype.toString.call(val) === '[object String]');
}
console.log(isString('hello world!')); // true
console.log(isString(new String('hello world'))); // true

- 210
- 2
- 4
-
1If someone wants to know the source, it's https://github.com/lodash/lodash/blob/master/isString.js – Ricardo Canelas Oct 25 '19 at 16:25
You can use this function to determine the type of anything:
var type = function(obj) {
return Object.prototype.toString.apply(obj).replace(/\[object (.+)\]/i, '$1').toLowerCase();
};
To check if a variable is a string:
type('my string') === 'string' //true
type(new String('my string')) === 'string' //true
type(`my string`) === 'string' //true
type(12345) === 'string' //false
type({}) === 'string' // false
https://codepen.io/patodiblasi/pen/NQXPwY?editors=0012
To check for other types:
type(null) //null
type(undefined) //undefined
type([]) //array
type({}) //object
type(function() {}) //function
type(123) //number
type(new Number(123)) //number
type(/some_regex/) //regexp
type(Symbol("foo")) //symbol

- 671
- 6
- 17
-
2This is a cute little function, although I wouldn't use it personally and would rather just do ad-hoc type checks as needed, like `foo === null` or `typeof foo == "string"`. Downvotes *might* be because 1. this is maybe a bit non-idiomatic; although using `Object.prototype.toString` is common, I've never seen anyone pull the type out of the result like you do, only compare to exact values of possible results like `"[object String]"` 2. you don't explain what the regex does or why, and to JavaScript newbies this is likely very unclear, and 3. it's unclear why to prefer this over other answers. – Mark Amery Nov 26 '21 at 18:22
-
A ridiculous counterexample is `Object.assign('abc', { [Symbol.toStringTag]: 'notAString' })` - it's a string, but try passing it to `type`! – Gershom Maes May 19 '23 at 13:53
A simple and fast way to test can be using the constructor name attribute.
let x = "abc";
console.log(x.constructor.name === "String"); // true
let y = new String('abc');
console.log(y.constructor.name === "String"); // true
Performance

- 1,650
- 16
- 24
-
1your solution is the best here, and also works for other objects, as in the solution offered by @Orwellophile. – alex Apr 14 '22 at 09:22
-
-
Shorter would be `x.constructor === String` (and now it's also safe for cases where you have instances of some other class which also happens to be named `String`) – Gershom Maes May 19 '23 at 13:43
I also found that this works fine too, and its a lot shorter than the other examples.
if (myVar === myVar + '') {
//its string
} else {
//its something else
}
By concatenating on empty quotes it turns the value into a string. If myVar
is already a string then the if statement is successful.

- 1,578
- 16
- 28
-
5The only problem being that you're coercing a variable when you want to check it's type. That seems a bit expensive to me when compared with `typeof`. – Olical Sep 27 '13 at 18:29
-
1So yea, you're right. [jsperf](http://jsperf.com/typeof-function-vs-instanceof/9) said it was around 20% slow than `typeof` but still quite a bit faster than `toString`. Either way, I guess I just like the syntax for coercing. – Chris Dolphin Sep 30 '13 at 18:07
-
5this does not work with the String type; `var s = new String('abc'); > s === s + '' > false` – user5672998 Nov 06 '17 at 22:46
-
1Doesn't work with `new String` cus that creates a type of `object`. https://www.w3schools.com/js/tryit.asp?filename=tryjs_string_object2 – Chris Dolphin Nov 07 '17 at 03:55
-
1Good thought, but leaves out the edge case of object wrapped strings. – Anthony Rutledge May 12 '18 at 21:45
-
2I find this approach distasteful. Writing good code isn't about making it *shorter*. Its about *saying what you mean*. – ToolmakerSteve Jul 10 '21 at 22:23
-
I *think* this works, but it's pretty non-obvious why to someone who doesn't happen to know that doing `myVar + ''` will always produce a string regardless of the type of `myVar`. I agree with @ToolmakerSteve's take; this is needlessly clever to the point of being obfuscated, and I see no reason to use it over `typeof myVar == "string"`. – Mark Amery Nov 26 '21 at 18:40
var a = new String('')
var b = ''
var c = []
function isString(x) {
return x !== null && x !== undefined && x.constructor === String
}
console.log(isString(a))
console.log(isString(b))
console.log(isString(c))

- 612
- 7
- 10
-
Why do you need to check for null or undefined if x.constructor === String would also return false for null or undefined? – Jules Manson Jan 30 '18 at 02:20
-
2
The following method will check if any variable is a string (including variables that do not exist).
const is_string = value => {
try {
return typeof value() === 'string';
} catch (error) {
return false;
}
};
let example = 'Hello, world!';
console.log(is_string(() => example)); // true
console.log(is_string(() => variable_doesnt_exist)); // false

- 27,532
- 16
- 147
- 165
-
-1; the interface here is just weird. From the name I expect `is_string(x)` to tell me whether `x` is a string, but instead it tells me whether `x` is a callable that *returns* a string. Why would I want to pass in a function instead of passing my value directly? – Mark Amery Nov 26 '21 at 19:06
-
@MarkAmery This `is_string` function is for the purposes of checking if a variable exists and is a string. The arrow function being passed allows one to pass a variable that does not exist, whereas, normally, we would receive the error: "Uncaught ReferenceError: variable is not defined" if the variable didn't exist. The use case is similar to the Error Control Operator in PHP (i.e., `is_string(@$example)`). It may not the best or most common practice, but someone may find it useful, and that's what makes this answer unique from the others. – Grant Miller Nov 27 '21 at 02:35
A simple solution would be:
var x = "hello"
if(x === x.toString()){
// it's a string
}else{
// it isn't
}

- 157
- 1
- 6
-
1this doesn't **checks** if it's a string. It makes into a string, lots of things have `toString()` function – Muhammad Umer May 27 '15 at 00:13
-
7@MuhammadUmer Yes, it converts it into a string but then checks for identity against the original value, which will only be _True_ if the original value is also a string. – MrWhite Jun 01 '15 at 09:11
-
5this is wrong: you can't blindly call `.toString` on any values; try if the x to be checked is null or undefined, your code throw exception – user5672998 Nov 06 '17 at 20:54
-
1
-
Really? This solution seems too weird for me, because `toString()` method may be overridden and may throw an exception (due to some specific implementation), and your check will not work for sure. Main idea is that you shouldn't call methods that are not related to what you want to get. I'm not even talking about unnecessary overhead related to the `toString` method. Downvoting. – Rustem Zinnatullin Jan 28 '20 at 04:59
This is good enough for me.
WARNING: This is not a perfect solution. See the bottom of my post.
Object.prototype.isString = function() { return false; };
String.prototype.isString = function() { return true; };
var isString = function(a) {
return (a !== null) && (a !== undefined) && a.isString();
};
And you can use this like below.
//return false
isString(null);
isString(void 0);
isString(-123);
isString(0);
isString(true);
isString(false);
isString([]);
isString({});
isString(function() {});
isString(0/0);
//return true
isString("");
isString(new String("ABC"));
WARNING: This works incorrectly in the case:
//this is not a string
var obj = {
//but returns true lol
isString: function(){ return true; }
}
isString(obj) //should be false, but true

- 61
- 2
A Typechecker helper:
function isFromType(variable, type){
if (typeof type == 'string') res = (typeof variable == type.toLowerCase())
else res = (variable.constructor == type)
return res
}
usage:
isFromType('cs', 'string') //true
isFromType('cs', String) //true
isFromType(['cs'], Array) //true
isFromType(['cs'], 'object') //false
Also if you want it to be recursive(like Array that is an Object), you can use instanceof
.
(['cs'] instanceof Object //true
)

- 7,675
- 1
- 39
- 38
I'm going to go a different route to the rest here, which try to tell if a variable is a specific, or a member of a specific set, of types.
JS is built on ducktyping; if something quacks like a string, we can and should use it like a string.
Is 7
a string? Then why does /\d/.test(7)
work?
Is {toString:()=>('hello there')}
a string? Then why does ({toString:()=>('hello there')}) + '\ngeneral kenobi!'
work?
These aren't questions about should the above work, the point is they do.
So I made a duckyString()
function
Below I test many cases not catered for by other answers. For each the code:
- sets a string-like variable
- runs an identical string operation on it and a real string to compare outputs (proving they can be treated like strings)
- converts the string-like to a real string to show you
duckyString()
to normalise inputs for code that expects real strings
text = 'hello there';
out(text.replace(/e/g, 'E') + ' ' + 'hello there'.replace(/e/g, 'E'));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');
text = new String('oh my');
out(text.toUpperCase() + ' ' + 'oh my'.toUpperCase());
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');
text = 368;
out((text + ' is a big number') + ' ' + ('368' + ' is a big number'));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');
text = ['\uD83D', '\uDE07'];
out(text[1].charCodeAt(0) + ' ' + ''[1].charCodeAt(0));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');
function Text() { this.math = 7; }; Text.prototype = {toString:function() { return this.math + 3 + ''; }}
text = new Text();
out(String.prototype.match.call(text, '0') + ' ' + text.toString().match('0'));
out('Is string? ' + duckyString(text) + '\t"' + duckyString(text, true) + '"\n');
This is in the same vein as !!x
as opposed to x===true
and testing if something is array-like instead of necessitating an actual array.
jQuery objects; are they arrays? No. Are they good enough? Yeah, you can run them through Array.prototype
functions just fine.
It's this flexibility that gives JS its power, and testing for strings specifically makes your code less interoperable.
The output of the above is:
hEllo thErE hEllo thErE
Is string? true "hello there"
OH MY OH MY
Is string? true "oh my"
368 is a big number 368 is a big number
Is string? true "368"
56839 56839
Is string? true ""
0 0
Is string? true "10"
So, it's all about why you want to know if something's a string.
If, like me, you arrived here from google and wanted to see if something was string-like, here's an answer.
It isn't even expensive unless you're working with really long or deeply nested char arrays.
This is because it is all if statements, no function calls like .toString()
.
Except if you're trying to see if a char array with objects that only have toString()
's or multi-byte characters, in which case there's no other way to check except to make the string, and count characters the bytes make up, respectively
function duckyString(string, normalise, unacceptable) {
var type = null;
if (!unacceptable)
unacceptable = {};
if (string && !unacceptable.chars && unacceptable.to == null)
unacceptable.to = string.toString == Array.prototype.toString;
if (string == null)
;
//tests if `string` just is a string
else if (
!unacceptable.is &&
(typeof string == 'string' || string instanceof String)
)
type = 'is';
//tests if `string + ''` or `/./.test(string)` is valid
else if (
!unacceptable.to &&
string.toString && typeof string.toString == 'function' && string.toString != Object.prototype.toString
)
type = 'to';
//tests if `[...string]` is valid
else if (
!unacceptable.chars &&
(string.length > 0 || string.length == 0)
) {
type = 'chars';
//for each char
for (var index = 0; type && index < string.length; ++index) {
var char = string[index];
//efficiently get its length
var length = ((duckyString(char, false, {to:true})) ?
char :
duckyString(char, true) || {}
).length;
if (length == 1)
continue;
//unicode surrogate-pair support
char = duckyString(char, true);
length = String.prototype[Symbol && Symbol.iterator];
if (!(length = length && length.call(char)) || length.next().done || !length.next().done)
type = null;
}
}
//return true or false if they dont want to auto-convert to real string
if (!(type && normalise))
//return truthy or falsy with <type>/null if they want why it's true
return (normalise == null) ? type != null : type;
//perform conversion
switch (type) {
case 'is':
return string;
case 'to':
return string.toString();
case 'chars':
return Array.from(string).join('');
}
}
Included are options to
- ask which method deemed it string-y
- exclude methods of string-detection (eg if you dont like
.toString()
)
Here are more tests because I'm a completionist:
out('Edge-case testing')
function test(text, options) {
var result = duckyString(text, false, options);
text = duckyString(text, true, options);
out(result + ' ' + ((result) ? '"' + text + '"' : text));
}
test('');
test(null);
test(undefined);
test(0);
test({length:0});
test({'0':'!', length:'1'});
test({});
test(window);
test(false);
test(['hi']);
test(['\uD83D\uDE07']);
test([['1'], 2, new String(3)]);
test([['1'], 2, new String(3)], {chars:true});
- All negative cases seem to be accounted for
- This should run on browsers >= IE8
- Char arrays with multiple bytes supported on browsers with string iterator support
Output:
Edge-case testing
is ""
null null
null null
to "0"
chars ""
chars "!"
null null
chars ""
to "false"
null null
chars ""
chars "123"
to "1,2,3"

- 12,091
- 8
- 72
- 95
Implementation from lodash library v4.0.0
// getTag.js
const toString = Object.prototype.toString;
/**
* Gets the `toStringTag` of `value`.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function getTag(value) {
if (value == null) {
return value === undefined
? "[object Undefined]"
: "[object Null]";
}
return toString.call(value);
}
// isString.js
import getTag from "./getTag.js";
/**
* Checks if `value` is classified as a `String` primitive or object.
*
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a string, else `false`.
* @example
*
* isString('abc')
* // => true
*
* isString(1)
* // => false
*/
function isString(value) {
const type = typeof value;
return (
type === "string" || (type === "object" &&
value != null &&
!Array.isArray(value) &&
getTag(value) == "[object String]")
);
}
export default isString;

- 1,252
- 2
- 15
- 22
Just to expand on @DRAX's answer, I'd do this:
function isWhitespaceEmptyString(str)
{
//RETURN:
// = 'true' if 'str' is empty string, null, undefined, or consists of white-spaces only
return str ? !(/\S/.test(str)) : (str === "" || str === null || str === undefined);
}
It will account also for null
s and undefined
types, and it will take care of non-string types, such as 0
.
I have a technique that's stupid. But straightforward.
if(maybeAString.toUpperCase)
weHaveAString(maybeAString)
Yeah, it's far from perfect. But it is straightforward.

- 9,308
- 5
- 31
- 38
-
@Mike why would it throw an error? if there is no "toUpperCase" member then that would resolve to undefined which would fail the condition test like expected, without throwning any exception whatsoever. – Jun 22 '22 at 18:31
-
@andreyrk Did you even try it before you commented? Paste this into your JS console: `let x = 123; console.log(x.toUpperCase());` – Mike Jun 27 '22 at 16:04
-
@Mike Reread the answer and check if your code matches. Hint: `toUpperCase` is not the same as `toUpperCase()` – Jun 28 '22 at 15:18
-
1
-
1
-
@andreyrk that could still actually throw in case `maybeAString` is `null` or `undefined`. Worse, it can completely fail if we get a custom class that has a method or any property called `toUpperCase`. – Kaiido Jun 26 '23 at 06:24
isString() checks whether the passed argument is a string or not, using optional chaining and the latest standards:
const isString = (value) => {
return value?.constructor === String;
}

- 30,738
- 21
- 105
- 131

- 99
- 1
- 4
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);

- 602
- 2
- 5
- 18
We also can use isFinite() rather than typeof or isNAN(). Check this:
var name="somename",trickyName="123", invalidName="123abc";
typeof name == typeof trickyName == typeof invalidName == "string" ♀️
isNAN(name)==true
isNAN(trickyName)==false
isNAN(invalidName)==true
where:
isFinite(name) == false
isFinite(trickyName)== true
isFinite(invalidName)== true
So we can do:
if(!isFinite(/*any string*/))
console.log("it is string type for sure")
Notice that:
isFinite("asd123")==false
isNAN("asd123")==true

- 30,738
- 21
- 105
- 131

- 41
- 5
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)}`);
}

- 7,358
- 2
- 35
- 55
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

- 1,481
- 19
- 28
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,974
- 1
- 22
- 23
-
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) – Olical May 15 '17 at 08:49