is What? 🙉

Tiny, zero-dependency JavaScript type guards with first-class TypeScript support. Tree-shakable ESM by default.
npm i is-what
Or for deno available at: "deno.land/x/is_what"
Also check out is-where 🙈
Motivation
I built is-what because the existing solutions were all too complex or too poorly built.
I was looking for:
- A simple way to check any kind of type (including non-primitives)
- Be able to check if an object is a plain object
{} or a special object (like a class instance) ‼️
- Let TypeScript automatically know what type a value is when checking
And that's exactly what is-what is! (what a great wordplay 😃)
Usage
is-what is really easy to use, and most functions work just like you'd expect.
import { isString, isDate, isPlainObject } from 'is-what'
- Below are the most common functions (with a special note on
isNumber and isDate).
- Then we cover Objects (plain objects vs class instances).
- Finally we show TypeScript narrowing and
isObjectLike<T>.
Simple type check functions
isBoolean(true)
isBoolean(false)
isUndefined(undefined)
isNull(null)
isString('')
isEmptyString('')
isFullString('')
isHexDecimal('60adf084f0fbdcab42de841e')
isHexDecimal('60adf084f0fbdcab42de841e', 24)
isNumber(0)
isNumber('0')
isNumber(NaN)
isPositiveNumber(1)
isNegativeNumber(-1)
isArray([])
isEmptyArray([])
isFullArray([1])
isPlainObject({})
isEmptyObject({})
isFullObject({ a: 1 })
isFunction(function () {})
isFunction(() => {})
isDate(new Date())
isDate(new Date('invalid date'))
isMap(new Map())
isSet(new Set())
isWeakMap(new WeakMap())
isWeakSet(new WeakSet())
isRegExp(/\s/gi)
isSymbol(Symbol())
isBlob(new Blob())
isFile(new File([''], '', { type: 'text/html' }))
isError(new Error(''))
isPromise(new Promise((resolve) => {}))
isPrimitive('')
isIterable([1, 2, 3])
isIterable('hello')
isIterable(new Map())
isIterable(new Set())
isIterable(function* generator() {
yield 1
})
Let's talk about NaN
isNaN is a built-in JS Function but it really makes no sense:
typeof NaN === 'number'
isNaN('1')
isNaN('one')
With is-what the way we treat NaN makes a little bit more sense:
import { isNumber, isNaNValue } from 'is-what'
isNumber(NaN)
isNaNValue('1')
isNaNValue('one')
isNaNValue(NaN)
isPlainObject vs isAnyObject
Checking for a JavaScript object can be really difficult. In JavaScript you can create classes that will behave just like JavaScript objects but might have completely different prototypes. With is-what I went for this classification:
isPlainObject will only return true on plain JavaScript objects and not on classes or others
isAnyObject will be more loose and return true on regular objects, classes, etc.
const plainObject = { hello: 'I am a good old object.' }
class SpecialObject {
constructor(somethingSpecial) {
this.speciality = somethingSpecial
}
}
const specialObject = new SpecialObject('I am a special object! I am a class instance!!!')
isPlainObject(plainObject)
isAnyObject(plainObject)
getType(plainObject)
isPlainObject(specialObject)
isAnyObject(specialObject)
getType(specialObject)
Please note that isPlainObject returns true only for plain JavaScript objects.
Getting and checking for specific types
You can check for specific types with getType and isType:
import { getType, isType } from 'is-what'
getType('')
isType('', String)
If you want to make sure your object inherits from a particular class or matches a toStringTag value, use isInstanceOf():
import { isInstanceOf } from 'is-what'
isInstanceOf(new XMLHttpRequest(), 'EventTarget')
isInstanceOf(globalThis, ReadableStream)
TypeScript
is-what makes TypeScript know the type during if statements. This means that a check returns the type of the payload for TypeScript users.
function isNumber(payload: unknown): payload is number {
}
function fn(payload: string | number): number {
if (isNumber(payload)) {
return payload
}
return 0
}
isPlainObject and isAnyObject with TypeScript will declare the payload to be an object type with any props:
function isPlainObject(payload: unknown): payload is { [key: string]: unknown }
function isAnyObject(payload: unknown): payload is { [key: string]: unknown }
if (isPlainObject(payload) && payload.id) return payload.id
isObjectLike
If you want more control over what kind of interface/type is cast when checking for objects:
To cast to a specific type while checking for isAnyObject, can use isObjectLike<T>:
import { isObjectLike } from 'is-what'
const payload = { name: 'Mesqueeb' }
if (isAnyObject(payload)) {
}
if (isObjectLike<{ name: string }>(payload)) {
}
Please note: this library will not actually check the shape of the object, you need to do that yourself.
isObjectLike<T> works like this under the hood:
function isObjectLike<T extends object>(payload: unknown): payload is T {
return isAnyObject(payload)
}
Meet the family (more tiny utils with TS support)
Source code
It's litterally just these functions:
function getType(payload) {
return Object.prototype.toString.call(payload).slice(8, -1)
}
function isUndefined(payload) {
return getType(payload) === 'Undefined'
}
function isString(payload) {
return getType(payload) === 'String'
}
function isAnyObject(payload) {
return getType(payload) === 'Object'
}
See the full source code here.