When I first started writing TypeScript, it felt strange and bureaucratic, like I was being asked to constantly justify things that were already obvious.
Then, after enough time, you realise TypeScript isn’t being pedantic. It’s compensating for the fact that JavaScript itself is wildly permissive.
JavaScript’s type system has the energy of a witness being cross-examined.
Is this thing an object? "Yup"
An array? "Maybe"
Is it something, at least? "Probably, but it could be
null"Wait, is it a date? "Ah, you got me! Yeah, it's a date, lol…"
typeof {} // "object"
typeof [] // "object"
typeof null // "object"
typeof new Date() // "object"Which leads to half of modern frontend engineering becoming:
if (
value &&
typeof value === "object" &&
!Array.isArray(value) &&
!(value instanceof Date)
) {
// finally, maybe (not), a plain object
}JavaScript:
Everything is an object until proven otherwise.
TypeScript:
I would like to see the proof.
There’s a comical number of things that satisfy the "object" type, including:
ArraysnullDateMapSetRegExp- Errors
- Typed arrays (
Uint8Array, etc.) Promise- Boxed primitives (
new String("x")) - Class instances
- DOM nodes
URLArrayBufferWeakMap/WeakSet- Literally objects with custom prototypes
- Objects created with
Object.create(null)that aren’t even instances ofObject
So, if you don't want a type guard that starts to look like:
value &&
typeof value === "object" &&
!Array.isArray(value) &&
!(value instanceof Date) &&
!(value instanceof Map) &&
!(value instanceof Set)Just use this, which contains the accumulated trauma of an entire ecosystem:
isPlainObject(value)