Javascsript is weird, and TypeScript, by design, does not even try to do anything to improve it at runtime. In Javascript, there are two kind of string values - primitive values and objects (or boxed strings).
So you have to check for both, or settle on using only one kind of string throughout the code. Usual recommendation is to avoid using String
class at all. You can see the difference in javascript console:
let primitiveString = 'a';
>
typeof primitiveString === 'string'
> true // note that the result of runtime `typeof` is a string
primitiveString instanceof String
> false // primitiveString was not created with the String() constructor, of course
let objectString = new String('a');
>
typeof objectString === 'string'
> false // typeof objectString returns 'object'
primitiveString instanceof String
> true
objectString === primitiveString
> false
objectString == primitiveString
> true
I'd love something like
switch(typeof food) {
case string:
console.log(food)
case {value:string}:
console.log(food.value)
}
There are two different typeof
operators in TypeScript.
One is compile-time only, it allows to refer to a type of some variable or function.
Another one is run-time typeof
which is the same as in javascript, and it returns very limited amount of information because TypeScript does not generate any kind of type information available at runtime.
So, every time you want to check a type of the object at runtime, you need to write a series of if
statements with different kind of checks, as appropriate for the situation:
typeof
if you are checking for the kind of built-in type like string
, number
, booelan
, function
or object
(object
basically means "anything else")
instanceof
if you want to know which constructor was used to create an object (note that if the value was created as object literal, it will be instance of Object
, however it may well be compatible with some class because objects literals can have methods too)
in
operator if you want to check if an object has some property or method
Array.isArray()
to check if something is an array
and so on.
The compiler detects an error in your code
myValues.forEach(food => {
if (food instanceof String) {
console.log(food)
} else {
console.log(food.value) // <-- error here
}
})
because instanceof String
will be false for primitive strings, so the false
branch will be executed trying to access value
property which does not exists on strings. The usual way to check for a string type is
if (typeof food === 'string') {
as explained in another answer.