- Update 2022-07-10: new approach based on
Function.prototype.hasInstance()
In principle, the rule “typeof
is for primitive values, instanceof
is for objects” works. There are two exceptions:
- Checking if a value is an object
- Cross-realm instance checks
Neither typeof
nor instanceof
are good at checking if a value is an object.
Checking if a value is non-primitive via typeof
, is complicated:
const isObject = (v) => (
v !== null && (typeof v === 'object' || typeof v === 'function')
);
instanceof
can only be used for objects whose prototype chains end with Object.prototype
:
> Object.create(null) instanceof Object
false
> typeof Object.create(null)
'object'
> Object.prototype instanceof Object
false
> typeof Object.prototype
'object'
v instanceof C
only works if both v
and C
come from the current realm. In other cases, we can’t generally perform the check, but for some classes, there are workarounds:
Array.isArray(v)
typeof v === 'function'
The proposal introduces two features for cross-realm instance checks:
Symbol.typeMarker
lets us assign cross-realm symbols as type markers for classes.- All built-in classes get type markers.
Function.prototype.hasInstance(v)
is inherited by all functions and checks ifv
is an instance ofthis
.
The proposal also introduces one static method:
Object.isObject()
These are my first thoughts. I’m not attached to either specific names or many of the details.
To check if a value is primitive, use typeof
and ===
:
const categorize = (v) => ({
isUndefined: v === undefined,
isNull: v === null,
isBoolean: typeof v === 'boolean',
isNumber: typeof v === 'number',
isBigint: typeof v === 'bigint',
isString: typeof v === 'string',
isSymbol: typeof v === 'symbol',
});
To check if a value v
(that may or may not come from another realm) is an instance of a class C
, use C.hasInstance(v)
:
Map.hasInstance(valueFromAnotherRealm)
MyClass.hasInstance(valueFromAnotherRealm)
// Etc.
To determine if a value is an object, use Object.isObject()
:
> Object.isObject(Object.create(null))
true
> Object.isObject(Object.prototype)
true
More examples: see tests.
- Should the custom matchers proposed by ECMAScript Pattern Matching support
Symbol.typeMarker
?
Nice!
I never use typeof anymore, but always use constructor check, like:
You can check the constructor or the constructor name.
Works for me with all types (String, Array, Object, Number, Boolean, URL, Date, Function, AsyncFunction, ...), and also custom types.
Check also: https://github.com/hckrnews/validator and https://github.com/hckrnews/objects how i do type checking.
Your example of numbers: